大多数列表共有的项目

时间:2013-07-17 15:10:54

标签: c# list

给定一个列表列表(假设有5个列表,要有一个可以使用的实数),我可以相对轻松地找到所有5个列表共有的项目(参见Intersection of multiple lists with IEnumerable.Intersect())以下代码:

var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 2, 3, 4 };
var list3 = new List<int>() { 3, 4, 5 };
var listOfLists = new List<List<int>>() { list1, list2, list3 };
var intersection = listOfLists.Aggregate((previousList, nextList) => previousList.Intersect(nextList).ToList());

现在让我们说intersection最终包含0个项目。很可能有一些对象是4/5列表中常见的。我将如何以最有效的方式找到它们?

我知道我可以浏览4个列表的所有组合并保存所有结果,但该方法不能很好地扩展(最终必须在大约40个列表上完成)。

如果4个列表中没有共同的项目,那么将重复搜索以查找3/5列表共有的项目等。在视觉上,这可以通过网格点列表来表示,我们正在搜索重叠最多。

有什么想法吗?

编辑: 也许最好是查看每个点并跟踪它在每个列表中出现的次数,然后创建出现次数最多的点列表?

2 个答案:

答案 0 :(得分:6)

您可以从所有列表中选择所有数字(点),并按值对其进行分组。然后按组大小排序结果(即列出存在点的计数)并选择最常见的项目:

var mostCommon = listOfLists.SelectMany(l => l)
                            .GroupBy(i => i)
                            .OrderByDescending(g => g.Count())
                            .Select(g => g.Key)
                            .First();
// outputs 3

您可以将First()替换为Take(N),而不是仅使用第一项,而是取几个热门项目。


返回包含列表数量的项目(按列表数量排序):

var mostCommonItems = from l in listOfLists
                      from i in l
                      group i by i into g
                      orderby g.Count() descending
                      select new {
                         Item = g.Key,
                         NumberOfLists = g.Count()
                      };

用法(item是强类型匿名对象):

var topItem = mostCommonItems.First();
var item = topItem.Item;
var listsCount = topItem.NumberOfLists;

foreach(var item in mostCommonItems.Take(3))
    // iterate over top three items

答案 1 :(得分:1)

您可以先组合所有列表,然后使用字典策略查找列表的模式,如下所示。这使得它非常快:

/// <summary>
/// Gets the element that occurs most frequently in the collection.
/// </summary>
/// <param name="list"></param>
/// <returns>Returns the element that occurs most frequently in the collection.
/// If all elements occur an equal number of times, a random element in
/// the collection will be returned.</returns>
public static T Mode<T>(this IEnumerable<T> list) 
{
    // Initialize the return value
    T mode = default(T);

    // Test for a null reference and an empty list
    if (list != null && list.Count() > 0)
    {
        // Store the number of occurences for each element
        Dictionary<T, int> counts = new Dictionary<T, int>();

        // Add one to the count for the occurence of a character
        foreach (T element in list)
        {
            if (counts.ContainsKey(element))
                counts[element]++;
            else
                counts.Add(element, 1);
        }

        // Loop through the counts of each element and find the 
        // element that occurred most often
        int max = 0;

        foreach (KeyValuePair<T, int> count in counts)
        {
            if (count.Value > max)
            {
                // Update the mode
                mode = count.Key;
                max = count.Value;
            }
        }
    }

    return mode;
}