当项目相同时从可枚举源中删除单个项目

Bry*_*her 3 c# linq ienumerable

假设我有一个可枚举的源代码,如下所示:

IEnumerable<string> source = new [] { "first", "first", "first", "second" };
Run Code Online (Sandbox Code Playgroud)

我希望能够构造一个将返回此内容的LINQ语句:

"first", "first", "second"
Run Code Online (Sandbox Code Playgroud)

注意如何只有一个第一次消失.我不关心哪一个,因为在我的情况下,所有3个"第一个"被认为是平等的.我已经尝试了source.Except(new [] { "first" })但是剥离了所有实例.

Amy*_*y B 8

source
  .GroupBy(s => s)
  .SelectMany(g => g.Skip(1).DefaultIfEmpty(g.First()))
Run Code Online (Sandbox Code Playgroud)

对于每个组,跳过组的第一个元素并返回其余组 - 除非它不返回...在这种情况下,返回组的第一个元素.


source
  .GroupBy(s => s)
  .SelectMany(g => g.Take(1).Concat(g.Skip(2)))
Run Code Online (Sandbox Code Playgroud)

对于每个组,取第一个元素,然后从第三个元素开始 - 始终跳过第二个元素.

  • g.Single将提出异常.替换为g.First(),这将非常优雅(无效的操作异常:序列包含多个元素) (2认同)

Joh*_*ght 7

我认为大卫B的回答让你非常接近,但是在那里只有一个价值的情况下它不会删除价值,这就是我认为原始海报所寻求的.

这是一个扩展方法,它将删除所请求项的单个实例,即使这是最后一个实例.这反映了LINQ Except()调用,但只删除了第一个实例,而不是所有实例.

    public static IEnumerable<T> ExceptSingle<T>(this IEnumerable<T> source, T valueToRemove)
    {
        return source
            .GroupBy(s => s)
            .SelectMany(g => g.Key.Equals(valueToRemove) ? g.Skip(1) : g);
    }
Run Code Online (Sandbox Code Playgroud)

鉴于:{"one", "two", "three", "three", "three"}
通话source.ExceptSingle("three")结果{"one", "two", "three", "three"}

鉴于:{"one", "two", "three", "three"}
通话source.ExceptSingle("three")结果{"one", "two", "three"}

鉴于:{"one", "two", "three"}
通话source.ExceptSingle("three")结果{"one", "two"}

鉴于:{"one", "two", "three", "three"}
通话source.ExceptSingle("four")结果{"one", "two", "three", "three"}