示例:我有集合{1, 2, 3, 4}
。
我想得到所有(无序)对不同的元素,它们是:
{1,2}
,{1,3}
,{1,4}
,{2,3}
,{2,4}
,{3,4}
。
如果我有IList
,我可以这样做:
IList<MyType> list = ... // fill the list elements
for (int i = 0; i < list.Count - 1; i++)
for (int j = i+1; j < list.Count; j++)
{
... // now we have the pair of list[i] and list[j]
}
对于LinkedList
我也知道怎么做;除了索引i
和j
之外,我们有两个LinkedListNode
s fst
和snd
,它几乎相同。每当我们致电fst.Next
时,我们都会设置snd = fst.Next
。
对于n
元素的列表,上述方法需要(n-1)*n/2
个迭代步骤。 (对于i = 0
,我们有j = 1 ... n-1
,所以n-1
步。对于i = 1
,我们有j = 2 ... n-1
,所以n-2
步。等等。总计最多(n-1) + (n-2) + ... + 3 + 2 + 1 = (n-1)*n/2
步。)
对于任何ICollection
,有没有办法做到这一点?我认为IEnumerator
可以做到这一点,但似乎没有办法告诉IEnumerator
“移动到那个参考!”就像我可以用LinkedListNode
s。
编辑:
我不是在寻找这个解决方案:
foreach (MyType a in list)
foreach (MyType b in list)
{
if (a == b)
continue;
... // now we have the pair of a and b
}
对于n
个元素的集合,此方法需要n^2
个迭代步骤,这比上述方法略长一倍,因此显然效果不佳。
编辑:
事先将集合转换为List
似乎是最简单的方法,对于大型n
,性能损失可以忽略不计,因为它只会为整个交互添加n
个步骤(新列表必须由n
元素填充。所以我会坚持下去。
答案 0 :(得分:2)
编辑:根据评论中的讨论和编辑过的问题,似乎在列表中复制可枚举是最好的行动方案。
旧答案:
在我看来,您需要将项目放入某种哈希表数据结构中。
这是一个使用GroupBy的基于LINQ的解决方案
var items = new List<int> { 1, 2, 3, 2, 3 };
var groupedItems = from i in items
group i by i into g
select g;
foreach (var group in groupedItems)
{
//group.Key stores the key of the grouping
foreach (var item in group) //group contains items with the same key
{
//Do something
Console.WriteLine(item);
}
}
此处每个组都包含具有相同键的项(在此示例中,因为项是int,项是键,但您可以按所需的任何表达式进行分组)
或者,您可以使用字典自行分组内容
var items = new List<int> { 1, 2, 3, 2, 3 };
var itemsDictionary = new Dictionary<int, List<string>>();
foreach (int i in items)
{
List<string> repeatedValues;
if(itemsDictionary.TryGetValue(i, out repeatedValues))
{
repeatedValues.Add(i.ToString());
}
else
{
itemsDictionary.Add(i, new List<string> { i.ToString() });
}
}
foreach (KeyValuePair<int, List<string>> kvp in itemsDictionary)
{
//do whatever is needed kvp.Value
}
在这个例子中,我使用了一个字符串来模拟int的键和不同类型的值。我认为这两个解决方案都是NlogN
或者 - 在列表中对集合进行排序 - 所有相等的元素将一个接一个地放置。这将是NlogN解决方案。
答案 1 :(得分:2)
IEnumerable
是一个仅向前的迭代器; ICollection
没有索引访问权限。您可以做的是在第一次迭代期间将可枚举放入缓冲区,然后使用嵌套的for
循环。
var enumerable = Enumerable.Range(0, 10);
var buffer = new List<int>();
using (var enumerator = enumerable.GetEnumerator())
{
if (enumerator.MoveNext())
{
buffer.Add(enumerator.Current);
while (enumerator.MoveNext())
{
var current = enumerator.Current;
buffer.Add(current);
Handle(buffer[0], current);
}
}
}
for (int i = 1; i < buffer.Count - 1; i++)
for (int j = i + 1; j < buffer.Count; j++)
Handle(buffer[i], buffer[j]);
或者,如果您不再关心再次浏览这些项目,可以使用enumerable.ToArray()
,然后在该数组上使用嵌套的for
。