Linq查询将重复项的子集减少到更大集合中的单个值?

时间:2010-11-05 23:34:00

标签: c# linq

是否有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 }

感谢。

5 个答案:

答案 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);