我想实现一个方法,它将一个未知类型的集合作为参数,并返回一个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循环i循环遍历所有剩余的循环。我看到的问题是方法col.ElementAt(i)。如果我们查看源代码,我们会看到如果&#39; col&#39;是IList类型,然后这直接获得给定索引处的值,但是采用任何其他集合,这将非常缓慢并且将花费大量时间。 我尝试使用foreach循环(注释部分)处理这个问题,这在使用IEnumerable时是有效的,但是这部分不起作用,因为枚举器对于内部循环和外部循环都是通用的,因此这会产生一组所有2元组,其中一些重复。 有人会给我一些建议,如何改进这段代码?
答案 0 :(得分:0)
问题是Enumerable旨在描述一个可以迭代它的类(如流)。它无意支持有效的随机访问(如数组)。
在使用Count()的地方,你强迫Enumerable迭代到它的结尾,所以在Stream的情况下,这将等到读取整个流。当然,Stream可能不支持高效的直接访问,甚至不能在内存中缓冲其内容(记住 - 它只是支持枚举) - 因此随后调用ElementAt()可能会强制它从开头重新读取到指示的位置。
解决此问题的最佳方法是从IEnumerable切换到IList。这意味着它确实支持随机访问;显然它仍然可能表现不佳,但这不是你职能的责任。