【问题标题】:Finding 2-Tuple Combinations of IEnumerable<T> collection, C#查找 IEnumerable<T> 集合的 2 元组组合,C#
【发布时间】:2018-01-29 09:21:44
【问题描述】:

我想实现一个方法,它将未知类型的集合作为参数,并返回一个 2 元组的集合,其中包含来自这些元素的所有可能的不同组合(没有重复)。我的代码:

public static IEnumerable<Tuple<T, T>> Get2Combinations<T>(this 
IEnumerable<T> col)
    {
        /*foreach (var item1 in col)
        {
            col.GetEnumerator().MoveNext();
            foreach (var item2 in col)
            {
                yield return new Tuple<T, T>(item1, item2);
            }
        }*/
        for (int i = 0; i < col.Count(); i++)
        {
            for (int j = i + 1; j < col.Count(); j++)
            {
                yield return new Tuple<T, T>(col.ElementAt(i), 
col.ElementAt(j));
            }
        }
    }

我正在做的是我取第一个元素并与其他元素取一对。然后使用这个内部 for 循环,我遍历所有剩余的循环。我看到的问题是方法 col.ElementAt(i)。如果我们查看源代码,我们会看到如果 'col' 是 IList 类型,那么它会直接获取给定索引处的值,但是如果采用任何其他集合,这将非常缓慢并且需要很多时间。 我尝试使用 foreach 循环(注释部分)来处理这个问题,这在使用 IEnumerable 时很有效,但是这部分不起作用,因为枚举器对于内部和外部循环都是通用的,因此这会产生所有 2 -元组,其中一些重复。 谁能给我一些建议,如何改进这段代码?

【问题讨论】:

    标签: c# collections combinations combinatorics


    【解决方案1】:

    问题在于 Enumerable 旨在描述一个可以迭代它的类(如流)。它不打算支持有效的随机访问(如数组)。

    在您使用 Count() 的地方,您强制 Enumerable 将自身迭代到其末尾,因此在 Stream 的情况下,这将等到整个流被读取。当然,Stream 可能不支持有效的直接访问,甚至不支持在内存中缓冲其内容(请记住 - 它只是承诺支持枚举) - 因此随后调用 ElementAt() 可能会强制它从头开始重新读取到指定的位置。

    解决此问题的最佳方法是将 IEnumerable 转换为 IList。这意味着它确实支持随机访问;显然它仍然可能表现不佳,但这不是您的职能的责任。

    【讨论】:

    • 另一点:IEnumerable&lt;T&gt; col 可能是无限的,然后整个概念就崩溃了……
    • 好点 - IEnumerable 只需要实现 GetEnumerator()。 Count() 方法是不属于接口的扩展方法,在无限集合的情况下,它会(可能)挂起。
    • 我检查了参考来源:如果计数器溢出,它将抛出。不过,可能还要等一段时间……
    猜你喜欢
    • 1970-01-01
    • 2017-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    相关资源
    最近更新 更多