Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 保留重复项的两个列表之间的差异_C#_Linq - Fatal编程技术网

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

C# 保留重复项的两个列表之间的差异,c#,linq,C#,Linq,我有两份清单: var list1 = new List<string> { "A", "A", "B", C" }; var list2 = new List<string> { "A", "B" }; 其中,列表是从list1中删除的list2中的所有元素,我认为没有Linq扩展方法,因为除外会删除重复项 实现这一点的非linq方法是: var tempList = list1.ToList(); foreach(var item in list2) { t

我有两份清单:

var list1 = new List<string> { "A", "A", "B", C" };
var list2 = new List<string> { "A", "B" };
其中,列表是从
list1
中删除的
list2
中的所有元素,我认为没有Linq扩展方法,因为
除外
会删除重复项

实现这一点的非linq方法是:

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;
    }
}

不是LINQ,而是一行:

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

顺便说一句。。。如果
List
具有类似于
AddRange
的功能,但同时删除一组项,那就太好了。

如果您不关心结果元素的顺序,可以使用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();
var a=新列表{“a”、“a”、“B”、“C”};
var b=新列表{“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();
这是一本书

我必须承认,你的解决方案比我的简单得多,所以它应该被视为仅仅是一种好奇,一种证明LINQ也可以做到这一点的方法


其工作原理如下:对于第一个列表中的每个元素,我们添加一个带有
1
的键值对;对于第二个列表中的每个元素,我们添加一个键值对,其值为
-1
。然后,我们按照元素的键对所有元素进行分组,将它们的键和负的键相加,并生成尽可能多的键,确保在结果为负时不选择任何内容。

看看您的示例,我认为您的意思是“从列表1中删除列表2中的所有元素”:


@dasblinkenlight变成了一个扩展,让他简化它。我想有时候Linq不是答案。@Romoku你是对的。为了解释堆栈溢出模因,有时它是这样的:“我有一个问题;我想用Linq解决它;现在我有两个问题:)用X替换Linq,你就有了模因的一般形式。@Romoku最初的模因是关于regex的,但模因确实非常通用。列表的大小是任意的,任何一个都可能更大。这里没有关于列表的相对大小的假设。哦,我猜我误解了你所说的“从列表1中删除列表2中的所有元素”的意思。我选择这个答案是正确的,因为它比linqpad中的@dasblinkenlight运行得更快。@Ani这太棒了!
list2.ForEach(l => list1.Remove(l));
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();
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;