【问题标题】:Comparing entries of 2 dictionaries by their values but then return their respective keys?按它们的值比较两个字典的条目,然后返回它们各自的键?
【发布时间】:2019-12-03 20:45:47
【问题描述】:

我有两个 Dictionary<int, (int, int)> 类型的字典,第一个 int 是它们的键,(int, int) 是它们的值。

使用var intersections = dict1.Values.Intersect(dict2.Values);,我可以比较值并返回一个 IEnumerable,其中包含两者之间重合的所有值,但这并没有给我密钥。并且使用var intersections = dict1.Keys.Intersect(dict2.Keys); 将返回出现在两个字典中的键,即...每个键,因为键刚从 1 开始,每个条目递增 1,所以没用。

我想通过它们的值比较条目,然后访问它们的键。因此,例如,如果条目 (12, 36) 出现在 dict1 的 Key 20 和 dict2 的 Key 45 上,我想有一种访问 20 和 45 的方法。

我完全不知所措。我能够比较值和返回值,我能够比较键和返回键,但我无法比较值和返回键。怎么做?

谢谢!

【问题讨论】:

  • 描述你试图解决的问题,而不是描述你无法实现的问题的解决方案。
  • 任何值不可能在任一字典中出现多次吗?
  • Dictionary 的值不保证是唯一的。那么,考虑到这两个字典可能有匹配的重复值,相交操作的预期输出是什么?例如dict1: {{1 => "A"}, {2 => "A"}}dict2: {{11 => "A"}, {12 => "A"}}。输出应将值"A" 与第一个字典的键1, 2 和第二个字典的11, 12 相关联。你想要Dictionary<TValue, (List<TKey>, List<TKey>)> 类型的输出吗?

标签: c# linq dictionary intersect


【解决方案1】:
dict1.Union(dict2)
    .GroupBy(kvp => kvp.Value)
    .Where(g => g.Count() > 1) // but this doesn't account for equal values in same dictionary if that's important
    .Select(g => new
    {
        Value = g.Key,
        Keys = g.Select(kvp => kvp.Key),
    });

或者,您可以加入每个字典的KeyValuePair<TKey,TValue> 对象的Value 属性。

【讨论】:

  • 在定义Keys 时,您可能希望拥有ToList
【解决方案2】:

您可以简单地使用Where 过滤器并检查其他字典是否包含该值:

var matches = dict1.Where(d => dict2.ContainsValue(d.Value));

这将返回一个可枚举,然后您可以根据需要使用 ToDictionary()ToList()

编辑:

使用此Union 返回匹配的双方:

dict1.Where(d => dict2.ContainsValue(d.Value))
     .Union(dict2.Where(d => dict1.ContainsValue(d.Value)));

HTH

【讨论】:

  • @SebC 这应该可以按需要工作。看到这个小提琴:dotnetfiddle.net/k2WBLB
  • 似乎是最好的选择,是的,并且非常适合小样本,非常感谢! :) 对于更大的样本(找到数千个匹配项),这似乎冻结了所有内容,尽管可能只需要花费大量时间来计算它基本上看起来像冻结..这个 var 变成了什么样的变量?它只是说“(局部变量)?”。在不知道我正在使用哪种变量的情况下,很难在将结果发送到 foreach 之前仅过滤掉一部分结果(我正在寻找一堆中较小的键)。
  • 更新:计算大约 10 分钟后解冻啊。但我确实得到了我想要的清单,非常感谢各位的帮助! :)
【解决方案3】:

您可以创建自己的 IEqualityComparer 并使用需要它的 Intersect 重载。

static void Main(string[] args)
{
    var dict1 = new Dictionary<int, (int, int)>();
    dict1.Add(1, (1, 1));
    dict1.Add(2, (2, 2));
    dict1.Add(3, (3, 3));
    var dict2 = new Dictionary<int, (int, int)>();
    dict2.Add(4, (2, 2));
    dict2.Add(5, (3, 3));
    dict2.Add(6, (4, 4));

    var intersection = dict1.Intersect(dict2, new eq());

    foreach (var i in intersection)
        Console.WriteLine($"Key: {i.Key}, Value: {i.Value}");
    Console.ReadLine();
}

class eq : IEqualityComparer<KeyValuePair<int, (int, int)>>
{
    public bool Equals(KeyValuePair<int, (int, int)> x, KeyValuePair<int, (int, int)> y)
    {
        return x.Value == y.Value;
    }

    public int GetHashCode(KeyValuePair<int, (int, int)> obj)
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 23 + obj.Value.Item1;
            hash = hash * 23 + obj.Value.Item2;
            return hash;
        }
    }
}

键:2,值:(2, 2)
键:3,值:(3, 3)

来自 Jon Skeet 的 this answer 的哈希

【讨论】:

  • 哦,这几乎是完美的!然而这看起来它也在比较键,而我只想比较值然后返回附加到它的键。在您的示例中,如果 (2,2) 设置为 dict1 中的 Key 2,但设置为 dict2 中的 Key 5,我仍然希望找到这对,并获得 2 + 5 作为结果。
  • @SebC 阅读评论清楚地表明 intersect 是不对的。也许还有更多的工作......我会考虑的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-06
  • 1970-01-01
  • 2018-10-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多