在字典中查找重复列表并打印重复列表的键

Finding duplicate lists in dictionary and print Key of the duplicated list

如果有完全匹配的值列表,我有兴趣在字典中查找键

下面是一个字典,其中有与 class 关联的学生列表。

var studentsInClass = new Dictionary<string, List<string>>();

studentsInClass.Add("Maths", new List<string> { "James", "Bob", "Sophia" });
studentsInClass.Add("English", new List<string> { "James", "Bob", "Sophia", "Mel" });
studentsInClass.Add("History", new List<string> { "Hannah" });
studentsInClass.Add("Geography", new List<string> { "Paul", "Zack" });
studentsInClass.Add("Art", new List<string> { "Paul", "Zack" });
   

例如,我希望将 classes/keys 地理艺术 视为 保罗Zack(而且只有这两个)在这两个 class 中。 JamesBobSophia 都在 Math EnglishMelEnglish,所以不是完全匹配。

我在这里关注了一个类似的问题Finding duplicate values in dictionary and print Key of the duplicate element

但我认为这不适用于列表或引用类型

您可以按通过连接字典中的列表项创建的字符串进行分组。这样,您就可以避免比较两个具有相同项目但指向不同引用的列表的问题。

var groups = studentsInClass.GroupBy(x => string.Join("", x.Value)).Where(x => x.Count() > 1);

在这里,如果这些组有多个项目,则对这些组进行分组和过滤,在您的示例中为地理和艺术。

在线演示:https://dotnetfiddle.net/Up72sw

注意:上面的代码会考虑学生的顺序。如果 Geography 是“Zack”、“Paul”,它不会将其识别为相同的。如果您想忽略商品的顺序,请在加入它们之前对您的商品进行排序:

var groups = studentsInClass.GroupBy(x => string.Join("", x.Value.OrderBy(y => y))).Where(x => x.Count() > 1);

Linq 可以使这个示例变得更好一些,但由于我猜这是入门课程的练习,所以我用循环完成了它。

            var studentsInClass = new Dictionary<string, List<string>>();

            studentsInClass.Add("Maths", new List<string> { "James", "Bob", "Sophia" });
            studentsInClass.Add("English", new List<string> { "James", "Bob", "Sophia", "Mel" });
            studentsInClass.Add("History", new List<string> { "Hannah" });
            studentsInClass.Add("Geography", new List<string> { "Paul", "Zack" });
            studentsInClass.Add("Art", new List<string> { "Paul", "Zack" });

            var identicalClasses = new Dictionary<string, List<string>>();
            /*iterate all key-value pairs in the just created dictionary*/
            foreach (KeyValuePair<string, List<string>> entry in studentsInClass)
            {
                foreach (KeyValuePair<string, List<string>> entry2 in studentsInClass)
                {
                    /* first we check if we're verifying a key that isn't the entry key itself.
                     * Secondly, we check if the list contains all elements in the second list.
                     * Finally, we make sure the lists are the same size.
                     */ 
                    if (entry.Key != entry2.Key && entry.Value.All(entry2.Value.Contains) && entry.Value.Count == entry2.Value.Count) //If order matters, you can use entry.Value.SequenceEqual(entry2.Value)
                    {
                        /*add the key-value pair to a dict which we can use somewhere else.*/
                        identicalClasses.Add(entry.Key, entry.Value);
                        //Just to show the keys we've added to our identicalClasses list
                        Console.WriteLine("key = " + entry.Key);
                        //We need to break since we don't want to list the key multiple times should there be more than 2 identical classes.
                        break;
                    }
                }
            }

如果顺序很重要,那么您可以利用 Enumerable.SequenceEqual

我能想到的最简单的解决方案:

foreach(var lhs in studentsInClass)
    foreach(var rhs in studentsInClass)
    {
        if(lhs.Key == rhs.Key) continue;
        if(Enumerable.SequenceEqual(lhs.Value, rhs.Value))
            Console.WriteLine(lhs.Key + " + " + rhs.Key);
    }

这将打印:

Geography + Art
Art + Geography