假设我有一个可枚举的来源,看起来像这样:
IEnumerable<string> source = new [] { "first", "first", "first", "second" };
我希望能够构造一个返回它的LINQ语句:
"first", "first", "second"
注意只有一个第一次消失了。我不关心哪一个,因为在我的情况下,所有3个“第一个”被认为是平等的。我已经尝试了source.Except(new [] { "first" })
但是将所有实例删除了。
答案 0 :(得分:8)
source
.GroupBy(s => s)
.SelectMany(g => g.Skip(1).DefaultIfEmpty(g.First()))
对于每个组,跳过组的第一个元素并返回其余组 - 除非这将返回无...在这种情况下,返回组的第一个元素。
source
.GroupBy(s => s)
.SelectMany(g => g.Take(1).Concat(g.Skip(2)))
对于每个组,取第一个元素,然后从第三个元素开始 - 总是跳过第二个元素。
答案 1 :(得分:6)
我认为David B的回答让你非常接近,但是在那里只有一个值的情况下它不会删除它,这就是我认为原始海报所寻找的。 p>
这是一个扩展方法,它将删除所请求项的单个实例,即使这是最后一个实例。这反映了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);
}
鉴于:{"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"}
答案 2 :(得分:3)
我想出了一个单线LINQ语句来做到这一点。它需要一个单独的标志变量。我将其实现为扩展方法:
public static IEnumerable<T> ExceptOne<T>(this IEnumerable<T> enumerable, T element)
{
var i = 0;
return enumerable.Where(original => !EqualityComparer<T>.Default.Equals(original, element) || ++i > 1);
}
我使用了int,以防我后来想要添加“numberToRemove”参数(将&gt; 1更改为&gt; numberToRemove)。 YAGNI和所有这一切,但无论如何它都像布尔一样可读。
答案 3 :(得分:1)
IEnumerable<string> source = new [] { "first", "first", "first", "second" };
List<string> newSource = new List<string>();
var foo = source.GroupBy (s => s).Select (s => new KeyValuePair<string,int>(s.Key, (s.Count()>1)?s.Count()-1:s.Count ()));
foreach (var element in foo)
{
newSource.AddRange(Enumerable.Repeat(element.Key,element.Value));
}
这里非常努力。基本上,这将创建原始的第二个列表,每个不同的密钥和实例的数量,如果有多个,则扣除一个,然后重新渲染具有正确数量的元素的列表。
不如大卫B的回答那么优雅,但我已经写过了,但我也可以将其作为另一个可能的答案发布。我确信foreach可以用于Linq语句,但是已经很晚了,我的大脑不能正常工作!
答案 4 :(得分:0)
我对LINQ并不是很熟悉,但这里有一些你可能想要使用的流程:
将所有独特项目存储在新列表B中,即:
A: {1, 1, 1, 2, 4, 4, 6}
变为
B: {1, 2, 4, 6}
通过B迭代,如果存在,则删除A中的实例,即:。
A: {1, 1, 1, 2, 4, 4, 6}
变为
F: {1, 1, 2, 4, 6}
希望这有帮助!