linq 保留重复项的两个列表之间的差异

jhkqcmku  于 2022-12-15  发布在  其他
关注(0)|答案(3)|浏览(123)

我有两个清单:

var list1 = new List<string> { "A", "A", "B", "C" };
var list2 = new List<string> { "A", "B" };

我想列一个清单

var result = new[] { "A", "C" };

这里的列表是list1中所有从list2中删除的元素,我认为没有Linq扩展方法,因为Except删除了重复的元素。
非线性的方法是:

var tempList = list1.ToList();
foreach(var item in list2)
{
    tempList.Remove(item);
}

但我想知道是否有一个Linq扩展方法我可能错过了。
编辑:
因为可能没有,所以我做了一个扩展方法。

public static class LinqExtensions
{
    public static IEnumerable<T> RemoveRange<T>(this IEnumerable<T> source, IEnumerable<T> second)
    {
        var tempList = source.ToList();
            
        foreach(var item in second)
        {
            tempList.Remove(item);
        }
        
        return tempList;
    }
    
    public static IEnumerable<TFirst> RemoveMany<TFirst, TSecond>(this IEnumerable<TFirst> source, IEnumerable<TSecond> second, Func<TSecond, IEnumerable<TFirst>> selector)
    {
        var tempList = source.ToList();
            
        foreach(var item in second.SelectMany(selector))
        {
            tempList.Remove(item);
        }
        
        return tempList;
    }
}

用法:

list1.RemoveRange(list2)
b0zn9rqh

b0zn9rqh1#

看一下你的例子,我认为你的意思是“从list1中删除list2中的所有元素”:

var lookup2 = list2.ToLookup(str => str);

var result = from str in list1
             group str by str into strGroup
             let missingCount 
                  = Math.Max(0, strGroup.Count() - lookup2[strGroup.Key].Count())
             from missingStr in strGroup.Take(missingCount)
             select missingStr;
kzmpq1sx

kzmpq1sx2#

不是LINQ,而是一行代码:

list2.ForEach(l => list1.Remove(l));

顺便说一句...如果List<int>有类似AddRange的东西,但是同时删除一堆项目,那就太好了。

nzrxty8p

nzrxty8p3#

如果您不关心结果元素出现的顺序,可以使用LINQ的GroupBy

var a = new List<string>{"A","A", "B", "C"};
var b = new List<string>{"A", "B"};
var res  =  a.Select(e => new {Key=e, Val=1})
    .Concat(b.Select(e => new {Key=e, Val=-1}))
    .GroupBy(e => e.Key, e => e.Val)
    .SelectMany(g => Enumerable.Repeat(g.Key, Math.Max(0, g.Sum())))
    .ToList();

这是一个demo on ideone
我必须承认,您的解决方案比我的简单得多,所以它应该被看作是一种纯粹的好奇心,一种证明这也可以用LINQ来完成的方法。
下面是它的工作原理:对于来自第一个列表的每个元素,我们添加具有1的键-值对;对于第二个列表中的每一个元素,我们添加一个键值对-1,然后我们按照键对所有元素进行分组,将它们的1和负的相加,并产生与总和一样多的键,确保当结果为负时我们不选择任何东西。

相关问题