如何计算列表 A 中存在于列表 B 中的每个数字的出现次数,如果不存在,则 return 为零?

How to count the occurence of each number in list A that is exist in list B and return zero if not existed?

这是我在这个社区中的第一个问题,我想得到我的问题的答案, 假设我有两个列表 A 和 B:

List<int> listA = new List<int>();
List<int> listB = new List<int>();

listA.Add(1);
listA.Add(2);
listA.Add(8);


listB.Add(1);
listB.Add(1);
listB.Add(1);
listB.Add(2);
listB.Add(2);
listB.Add(2);
listB.Add(2);

我想计算 listB 中已存在于 listA 中的每个元素的出现次数,如果不存在则加零:

这是我试过的:

var result = listB.GroupBy(x => x).ToDictionary(k => k.Key, v => v.Count());
foreach(var res in result.Values)
    Console.WriteLine(res); // it will print only {3,4} 

预期结果将是:

// { 3,4,0}  => 3 is the occurrences number of 1 , 4 is the occurrences number of 2 ,and 0 is the number occurrences of 8

我怎样才能达到这个结果?

在LINQ中使用left outer join是个好问题。这是一个article about it。这是最佳性能解决方案,因为您只需迭代一次集合,这对于大型集合或常用方法很重要。

这是您的问题的示例:

var result = from a in listA
    join b in listB.GroupBy(x => x) on a equals b.Key into gj
    from subList in gj.DefaultIfEmpty()
    select new
    {
        Number = a,
        Count = subList?.Count() ?? 0
    };

您也可以使用 GroupJoin 和方法链接,但我认为它更难阅读:

var result = listA
    .GroupJoin(listB.GroupBy(x => x), a => a, b => b.Key, (a, gj) => new { a, gj })
    .SelectMany(@t => @t.gj.DefaultIfEmpty(), (@t, subList) => new { Number = @t.a, Count = subList?.Count() ?? 0 });

之后,结果将包含一个匿名类型的集合,其中包含字段 NumberCount 以及 3 个元素:{1, 3}, {2, 4}, {8, 0}.

根据评论更新(感谢 Caius Jard):如果您不能使用 Null-Conditional Operator,您可以将其替换为显式检查:subList == null ? 0 : subList.Count()

我会使用 linq .Count() 扩展,它将计算满足条件的项目数。是的,这将比必要的次数更多地迭代列表,但它不会创建任何不必要的对象,而且它非常可读:

var countOccurences = new List<int>();
        
foreach (var inA in listA)
{
    countOccurences.Add(listB.Count(inB => inB == inA));
}
    
Console.WriteLine(string.Join(", ", countOccurences));

一旦循环开始工作,那么应该很容易看出它可以在一条语句中完成:

var countOccurences = listA.Select(inA => listB.Count(inB => inA == inB));

修复您的代码

var result = listB.GroupBy(x => x).ToDictionary(k => k.Key, v => v.Count());
foreach(var ent in listA)
    Console.WriteLine(result.ContainsKey(ent)?result[ent]:0); 

一行 Linq 语句

listA.Select(a => listB.Contains(a) ? a : 0 ).Select(r=>listB.Count(w=> w==r)).ToList();