如何在C#中的大多数列表中找到通用项(如果不能,则不是全部)

时间:2018-09-01 19:16:29

标签: c# list linq

我有这样的列表

List<List<uint>> AllLists = new List<List<uint>>();
List<uint> TestList1 = new List<uint>();
List<uint> TestList2 = new List<uint>();
List<uint> TestList3 = new List<uint>();
TestList1.Add(0x18A);
TestList1.Add(0x188);
TestList1.Add(0x188);
TestList1.Add(0x188);
TestList1.Add(0x188);
TestList1.Add(0x188);
TestList1.Add(0x188);
TestList1.Add(0x670);

TestList2.Add(0x670);
TestList2.Add(0x670);

TestList3.Add(0xBADC0DE); //this one is empty.. but could contain some useless ones (not 0x670).
AllLists.Add(TestList1.ToList());
AllLists.Add(TestList2.ToList());
AllLists.Add(TestList3.ToList());
List<uint> MostCommonOffset = FindCommon(AllLists);
  

列表1具有:0x18A,0x188,0x188,0x188,0x188,0x188,0x188,0x670
列表2具有:0x670,0x670
列表3为0xBADC0DE。

它应该得到答案0x670 ..即使第三个列表不包含答案,因为它是大多数列表中唯一的一个。

从理论上讲,如果第二个或第三个列表包含0x188,则最好使用它作为更好的答案,因为列表1中有很多它。并且它存在于2个列表中(大多数列表)。但它仍应同时给出答案0x6700x188

如果列表2或列表3也包含0x188,则答案应具有2个共同的答案。 0x6700x188

这是我以前使用的功能,但它需要在所有列表中找到一个匹配项。但这并不总是可能的。

   public static List<T> FindCommon<T>(List<List<T>> lists)
    {
        //This checks to make sure all commons are the same in all lists.
        List<uint> Counts = new List<uint>();
        List<List<T>> Matches = new List<List<T>>();
        bool Found = false;
        //List<T> curCheck;
        foreach (List<T> list in lists)
        {
            Found = false;
            for (int i = 0; i < Counts.Count; i++)
            {
                if (Matches[i].Count == list.Count)
                {
                    for (int j = 0; j < list.Count; j++)
                    {
                        //they not equals
                        if ((dynamic)Matches[i][j] != (dynamic)list[j])
                            goto next_loop;
                        //fully equal, increase count for repeated match found.
                        if (j == list.Count - 1)
                        {
                            Counts[i]++;
                            Found = true;
                            break;
                        }
                    }
                }
                next_loop:
                if (Found) break;
                continue;
            }

            if (!Found)
            {
                Counts.Add(1);
                Matches.Add(list);
            }
        }

        return Matches[Counts.IndexOf(Counts.Max())];
    }

这是一种简单的方法,它可以检查所有列表,但不会检查所有列表中最常见的列表,如果不能,则不会检查所有列表。

public static List<T> FindCommon<T>(params List<T>[] lists)
{
    //This checks to make sure all the commons that are partilly in all lists.

    return lists
        .SelectMany(x => x)
        .Distinct()
        .Where(item => lists.All(l => l.Contains(item)))
        .ToList();
}

1 个答案:

答案 0 :(得分:3)

LINQ解决方案有一些解释。也是LINQPad调试技巧。

List<List<uint>> AllLists = new List<List<uint>>();
List<uint> TestList1 = new List<uint>();
List<uint> TestList2 = new List<uint>();
List<uint> TestList3 = new List<uint>();
TestList1.Add(0x18A);
TestList1.Add(0x188);
TestList1.Add(0x188);
TestList1.Add(0x188);
TestList1.Add(0x188);
TestList1.Add(0x188);
TestList1.Add(0x188);
TestList1.Add(0x670);

TestList2.Add(0x670);
TestList2.Add(0x670);

TestList3.Add(0xBADC0DE); //this one is empty.. but could contain some useless ones (not 0x670).
AllLists.Add(TestList1.ToList());
AllLists.Add(TestList2.ToList());
AllLists.Add(TestList3.ToList());

var numbers = AllLists
    .Select(x => x
        .GroupBy(y => y)                    // group the numbers in each sub-list
        .Select(z => new { Key = z.Key }))  // select only the key in each sub-list
    .SelectMany(x => x)                     // flatten the lists
    .GroupBy(x => x.Key)                    // group by the keys
    .OrderByDescending(x => x.Count())      // sort the count of keys from largest to smallest
    ;

var mostCount = numbers
    .Select(x => x.Count())                 // select the count of keys only
    .Take(1)                                // take one, actually this line is not needed. you can remove it
    .FirstOrDefault();                      // take the largest count of key (the counts were sorted in previous linq statement)

var numberWithMostCount = numbers
    .Where(x => x.Count() == mostCount)     // filter the largest count of in the lists
    .Select(x => x.Key)                     // select the key only
    ;

foreach (var n in numberWithMostCount)
    Console.WriteLine(n);                   // print all key who has the largest count

您可能会注意到,在我先前的编辑中,我在LINQ语句中调用了一些Dump()方法。我在LinqPad中编写和调试了代码。它具有Dump()方法,可以轻松查看LINQ操作的结果。假设我在代码中放了一个Dump()方法(如果太小,请在新标签页中打开图片)。 Dump()方法显示LINQ方法的执行结果。您可以在每个Linq方法之后放置一个Dump()方法。尝试在任何带有注释的行中添加Dump()方法,最好一次添加一个或两个Dump()。

enter image description here

来自Lasse Vågsæther Karlsen的建议。使用Distinct()删除重复项。谢谢LasseVågsætherKarlsen。

var numbers = AllLists
    .Select(x => x.Distinct())              // remove duplicates
    .SelectMany(x => x)                     // flatten the lists
    .GroupBy(x => x)                        // group by the keys
    .OrderByDescending(x => x.Count())      // sort the count of keys from largest to smallest
    ;