设置减法,同时保留重复项

时间:2019-06-17 09:19:15

标签: c# linq

我需要在考虑重复项的同时获得两个字符串数组的集合减法

例如:

var a = new string[] {"1", "2", "2", "3", "4", "4"};
var b = new string[] {"2", "3"};
  

(a-b)=>预期输出=> string [] {“ 1”,“ 2”,“ 4”,“ 4”}

我已经尝试过Enumerable.Except(),它在减去后返回 unique 值:{ "1", "4" }这不是我想要的。

是否有一种无需定制实现的简单方法?

3 个答案:

答案 0 :(得分:3)

您可以尝试GroupBy,并与一起使用,例如

var a = new string[] {"1", "2", "2", "3", "4", "4"};
var b = new string[] {"2", "3"};

...

var subtract = b
  .GroupBy(item => item)
  .ToDictionary(chunk => chunk.Key, chunk => chunk.Count());

var result = a
  .GroupBy(item => item)
  .Select(chunk => new {
     value = chunk.Key,
     count = chunk.Count() - (subtract.TryGetValue(chunk.Key, out var v) ? v : 0)  
   })
  .Where(item => item.count > 0)
  .SelectMany(item => Enumerable.Repeat(item.value, item.count));

// Let's have a look at the result
Console.Write(string.Join(", ", result));

结果:

1, 2, 4, 4 

答案 1 :(得分:3)

通过利用下划线的Enumerable.ToLookup(可让您创建每个键具有多个值的类似字典的结构),您可以非常有效地完成此操作。在这里,由于在ILookup中不存在的键上进行键查找将返回空的IGrouping(而不是null或错误),因此可以避免一堆空检查/ {{ 1}}样板。因为TryGet...的值等于Enumerable.Take,所以我们也不必检查算术。

Enumerable.Take(0)

答案 2 :(得分:2)

尝试以下操作:

var a = new string[] { "1", "2", "2", "3", "4", "4" }.ToList();
var b = new string[] { "2", "3" };

foreach (var element in b)
{
    a.Remove(element);
}

已经过测试。