迭代HashSet中两个元素的每个组合

本文关键字:元素 组合 两个 迭代 HashSet | 更新日期: 2023-09-27 17:59:26

如何在HashSet中的两个元素的每个组合中迭代一次?

foreach (var elt1 in hashSet) {
  foreach (var elt2 in hashSet) {
    ...
  }
}

这将迭代两个的组合,但将迭代每个组合两次。我想做一次。

我认为用Python做这件事很容易。在C#中有什么方法可以做到这一点吗?

样品:

输入哈希集:{1,2,3,4}

迭代通过:(1,2)、(1,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);
}

*从技术上讲,您可以使用EnumerableElementAt<T>(int)扩展,但在大型集合上会非常缓慢。

迭代HashSet中两个元素的每个组合

我最初误解了这个问题。这是一个新的答案

这就是您想要的(如果可以选择基于工作索引)。下面有解释

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(苹果)时,j将为1(香蕉),然后为2(椰子),然后是3(西葫芦)

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

您可以直接在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);
    }
}

要返回所有排列(即(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);
 }