使用LINQ删除列表中的重复内容?

时间:2017-06-24 19:16:05

标签: c# .net linq

假设我有这个清单:

int[] list = { 1, 2, 3, 3, 1 };

我想要的是删除紧跟相同号码的重复项。所以在这种情况下我想删除3,但不是1。

因此,新列表应为:{1, 2, 3, 1}

另一个例子是这个列表:{2, 7, 7, 7, 2, 6, 4},它将成为{2, 7, 2, 6, 4}

我可以使用LINQ吗?

4 个答案:

答案 0 :(得分:5)

如果您想使用现有的LINQ方法,可以使用Aggregate,但这样的方法会失去懒惰。您可以编写自己的扩展方法:

public static IEnumerable<T> RemoveConsecutiveDuplicates<T>(this IEnumerable<T> source, IEqualityComparer<T> comp = null)
{
    comp = comp ?? EqualityComparer<T>.Default;

    using (var e = source.GetEnumerator())
    {
        if (e.MoveNext())
        {
            T last = e.Current;
            yield return e.Current;

            while (e.MoveNext())
            {
                if (!comp.Equals(e.Current, last))
                {
                    yield return e.Current;
                    last = e.Current;
                }
            }
        }
    }
}

答案 1 :(得分:3)

如果您坚持使用LINQ执行此操作,则可以使用instance Show (m (Maybe a)) => Show (MaybeT m a)

Aggregate

但由于每次迭代中var result = array.Aggregate(new List<int>(), (a, b) => { if (!a.Any() || a.Last() != b) a.Add(b); return a; }); Any,这不一定是最有效的解决方案。比较先前和当前迭代值的简单Last将表现得更好。

答案 2 :(得分:2)

您可以使用MoreLINQ中的PairWise,如下所示:

var result =
    new[] {list[0]}
        .Concat(
            list
                .Pairwise((x, y) => new {Item = y, Same = x == y})
                .Where(x => !x.Same)
                .Select(x => x.Item))
        .ToArray();

PairWise允许您获得一个序列,该序列源于对原始序列中的每个项目应用函数以及它之前的项目(期望第一个项目)。

我在这里做的是为每个项目(期望第一项),我得到项目本身和布尔值(Same),指示此项目是否等于它之前的项目。然后,我过滤序列只采取每个不等于它之前的项目的项目。然后,我只是将原始列表中的第一项附加到新序列。

注意:不要忘记处理list为空的情况。

答案 3 :(得分:1)

您可以执行以下操作(不使用linq)。

var collection = new [] { 2, 7, 7, 7, 2, 6, 4 }.ToList();
for (int i = 0; i < collection.Count - 1; i++)
{
    if (collection[i] == collection[i + 1])
    {
        collection.RemoveAt(i);
        i--;
    }
}

另一种基于收益率的解决方案就是这样。

public static IEnumerable<T> RemoveConsecutiveDuplicates<T>(this IEnumerable<T> collection)
{
    using (var enumerator = collection.GetEnumerator())
    {
        bool wasNotLast = enumerator.MoveNext(), 
             hasEntry = wasNotLast;
        T last = hasEntry ? enumerator.Current : default(T);

        while(wasNotLast)
        {
            if (!last.Equals(enumerator.Current))
                yield return last;

            last = enumerator.Current;
            wasNotLast = enumerator.MoveNext();
        }

        if (hasEntry)
            yield return last;
    }
}