从字典C#生成所有键对

时间:2014-11-30 12:53:35

标签: c# dictionary key combinations

我想创建一个存储在字典中的密钥对列表(顺序并不重要) 结果应类似于适用于数组结构的以下代码:

int[] myArray = new int[] {1,2,3,4,5,6,7,8,9};
List<Tuple<int, int>> list = new List<Tuple<int, int>>();

for (int i = 0; i < myArray.Length; i++)
    for (int j = i + 1; j < myArray.Length; j++)
        list.Add(new Tuple<int, int>(myArray[i], myArray[j]));

我想到的一件事是使用

创建密钥数组
Dictionary.Keys.ToArray()

方法,然后运行两个嵌套循环。 也许还有其他更有效的解决方案?

编辑: 最后的任务是创建一个矩阵,我可以将每个条目与所有其他条目进行比较 字典的值在此任务中并不重要。 我想创建一个包含所有键组合的列表(顺序并不重要)。

有没有更好的方法:

Dictionary<int, object> dict = new Dictionary<int, object>();
dict.Add(1, null);
dict.Add(2, null);
dict.Add(3, null);
dict.Add(4, null);
//...

int[] dictKeys = dict.Keys.ToArray();
List<Tuple<int, int>> list = new List<Tuple<int, int>>();

    for (int i = 0; i < dictKeys.Length; i++)
        for (int j = i + 1; j < dictKeys.Length; j++)
            list.Add(new Tuple<int, int>(dictKeys[i], dictKeys[j]));

4 个答案:

答案 0 :(得分:2)

你所拥有的只是产生结果的最简单方法。

虽然可以直接循环字典键,但您应该将它们视为一个数组,以便您可以通过索引轻松访问它们。

但是,在使用之前,您不必创建整个组合矩阵。您可以创建一个枚举器,在循环时创建矩阵:

public static IEnumerable<Tuple<int, int>> Combinations(IEnumerable<int> keys) {
  int[] a = keys.ToArray();
  for (int i = 0; i < a.Length; i++) {
    for (int j = i + 1; j < a.Length; j++) {
      yield return new Tuple<int, int>(a[i], a[j]);
    }
  }
}

用法:

foreach (Tuple<int, int> t in Combinations(myDictionary.Keys)) {
  // the pair of keys is t.Item1 and t.Item2
}

答案 1 :(得分:0)

也许这个Linq查询是你想要的:

List<Tuple<int, int>> content = dict.Keys.SelectMany(x => 
            dict.Keys, (x, y) => new Tuple<int,int>(x, y)).ToList();

对于带有键1, 2, 3的字典,它将提供9个元组:

(1,1)(1,2)(1,3)
(2,1)(2,2)(2,3)
(3,1)(3,2)(3,3)

答案 2 :(得分:0)

您可以使用生成笛卡尔积的方法:

public static class EnumerableExtensions
{
    public static IEnumerable<TResult> Cartesian<TFirst, TSecond, TResult>
                                      (this IEnumerable<TFirst> first, 
                                       IEnumerable<TSecond> second, 
                                       Func<TFirst, TSecond, TResult> resultSelector)
    {
        if (first == null) throw new ArgumentNullException("first");
        if (second == null) throw new ArgumentNullException("second");
        if (resultSelector == null) throw new ArgumentNullException("resultSelector");

        return from item1 in first
               from item2 in second
               select resultSelector(item1, item2);
    }
}

然后在你的钥匙上消费它:

IEnumerable<int> firstKeySet = dict.Keys;
IEnumerable<int> secondKeySet = dict.Keys;
IEnumerable<KeyValuePair<int, int>> cartasian = firstKeySet
                                                .Cartesian(secondKeySet, 
                                                          (k, v) => 
                                                           new KeyValuePair<int, int>
                                                          (k, v));

您可以在MoreLINQ内找到此内容以及更多内容。

答案 3 :(得分:0)

我会使用以下方法:

int[] myArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var query = from x in Enumerable.Range(0, myArray.Length)
            from y in Enumerable.Range(0, myArray.Length)
            select new Tuple<int, int>(x, y);

foreach (var tupel in query)
{
    Console.WriteLine(tupel);
}