我怎样才能在HashSet中迭代两个元素的每个组合?
foreach (var elt1 in hashSet) {
foreach (var elt2 in hashSet) {
...
}
}
这会迭代两个组合,但会迭代每个组合TWICE。我想做一次。
我认为在Python中很容易做到。有没有办法在C#中做到这一点?
样品:
输入hashSet:{1,2,3,4}
遍历:(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)
答案 0 :(得分:3)
在C#中没有内置方法可以做到这一点。由于HashSet<T>
未编入索引 * ,因此您无法使用两个循环执行此操作。
如果这是一次性交易,最简单的解决方案是对ToList()
或ToArray()
的结果进行两次嵌套循环,如下所示:
var items = hashSet.ToList();
for (var i = 0 ; i != items.Count ; i++) {
var a = items[i];
for (var j = i+1 ; j != items.Count ; j++) {
var b = items[i];
}
}
如果您正在寻找可重复使用的内容,请在生成所有对的IEnumerable<T>
上创建一个扩展方法:
static IEnumerable<Tuple<T,T>> MakeAllPairs<T>(this IEnumerable<T> data) {
var items = data.ToList();
for (var i = 0 ; i != items.Count ; i++) {
var a = items[i];
for (var j = i+1 ; j != items.Count ; j++) {
var b = items[i];
yield return Tuple.Create(a, b);
}
}
}
现在您可以在一个循环中迭代您的对:
foreach (var pair in hashSet.MakeAllPairs()) {
Console.WriteLine("{0} {1}", pair.Item1, pair.Item2);
}
* 从技术上讲,您可以使用ElementAt<T>(int)
中的Enumerable
扩展名,但对于大型集合,这会非常慢。
答案 1 :(得分:2)
我最初误解了这个问题。这是一个新答案
这就是你想要的(如果基于索引的工作是一个选项)。说明如下
string[] myArray = GetArray();
for (int i = 0; i < myArray.Length - 1; i++)
{
var element1 = myArray[i];
for(int j = i + 1; j < myArray.Length; j++)
{
var element2 = myArray[j];
Console.WriteLine("{0} {1}", element1, element2);
}
}
说明:假设以下数组:
Apple, Banana, Coconut, Zucchini
当i = 0
(Apple),j
为1(香蕉),然后是2(椰子),然后是3(Zucchini)
当i = 1
(香蕉)时,j
将是2(椰子),然后是3(西葫芦)。
等等......
基本上,您确保元素j始终位于元素i 之前。这意味着您已经有效地删除了一半的可能性(其中j在 i之前是),这就是您想要的。
注意:如果你想使用相同元素集(Apple + Apple),第二个for循环需要改为:
for(int j = i; j < myArray.Length; j++) //notice j = i instead of i + 1
答案 2 :(得分:0)
要返回所有排列(即(1,2)
和(2,1)
),您可以使用SelectMany
与自身交叉加入集合:
var hashSet = new HashSet<int>{1,2,3,4,5,6,7,8};
foreach (var elt in hashSet.SelectMany(
x => hashSet.Select(y => new Tuple<int, int>(x, y))))
{
Debug.WriteLine("{0}-{1}", elt.Item1, elt.Item2);
}
修改:如果您只想要唯一的组合(即(1,2)
而不是(2,1)
),那么只需在交叉连接期间添加一个过滤器值更大的值:
var hashSet = new HashSet<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
foreach (var elt in hashSet.SelectMany(
x => hashSet.Where(y => y >= x)
.Select(y => new Tuple<int, int>(x, y))))
{
Debug.WriteLine("{0}-{1}", elt.Item1, elt.Item2);
}
答案 3 :(得分:0)
您可以直接在HashSet上使用索引。 试试这个:
int int1, int2;
HashSet<int> hs = new HashSet<int>();
hs.Add(1);
hs.Add(2);
hs.Add(3);
for (int i = 0; i < hs.Count-1; i++) {
int1 = hs.ElementAt<int>(i);
for (int j = i + 1; j < hs.Count; j++)
{
int2 = hs.ElementAt<int>(j);
}
}