给定一个列表列表(假设有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列表共有的项目等。在视觉上,这可以通过网格点列表来表示,我们正在搜索重叠最多。
有什么想法吗?
编辑: 也许最好是查看每个点并跟踪它在每个列表中出现的次数,然后创建出现次数最多的点列表?
答案 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;
}