是否有linq命令可以过滤掉序列中出现的重复项?
'4'示例:
Original { 1 2 3 4 4 4 5 6 7 4 4 4 8 9 4 4 4 }
Filtered { 1 2 3 4 5 6 7 4 8 9 4 }
感谢。
答案 0 :(得分:5)
不是真的。我写这个:
public static IEnumerable<T> RemoveDuplicates(this IEnumerable<T> sequence)
{
bool init = false;
T current = default(T);
foreach (var x in sequence)
{
if (!init || !object.Equals(current, x))
yield return x;
current = x;
init = true;
}
}
答案 1 :(得分:4)
是的!单行代码和数组的一个循环。
int[] source = new int[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 };
var result = source.Where((item, index) => index + 1 == source.Length
|| item != source[index + 1]);
根据@ Hogan的建议,它可能会更好:
var result = source.Where((item, index) => index == 0
|| item != source[index - 1]);
我认为现在更具可读性。它意味着“选择第一个元素,以及那些不等于前一个元素的元素”。
答案 2 :(得分:3)
与svick的答案类似,除了副作用以避免缺点和逆转:
int[] source = new int[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 };
List<int> result = new List<int> { source.First() };
source.Aggregate((acc, c) =>
{
if (acc != c)
result.Add(c);
return c;
});
编辑根据mquander的关注点不再需要source.First()
:
int[] source = new int[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 };
List<int> result = new List<int>();
result.Add(
source.Aggregate((acc, c) =>
{
if (acc != c)
result.Add(acc);
return c;
})
);
我想我仍然最喜欢Danny的解决方案。
答案 3 :(得分:1)
您可以使用Aggregate()
(虽然我不确定它是否比非LINQ解决方案更好):
var ints = new[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 };
var result = ints.Aggregate(
Enumerable.Empty<int>(),
(list, i) =>
list.Any() && list.First() == i
? list
: new[] { i }.Concat(list)).Reverse();
我认为是O( n ),但我不完全确定。
答案 4 :(得分:0)
如果您使用的是.NET 4,那么您可以使用内置的Zip
方法执行此操作,但我可能更喜欢使用mquander's answer中显示的自定义扩展方法
// replace "new int[1]" below with "new T[1]" depending on the type of element
var filtered = original.Zip(new int[1].Concat(original),
(l, r) => new { L = l, R = r })
.Where((x, i) => (i == 0) || !object.Equals(x.L, x.R))
.Select(x => x.L);