Linq - 本地不同

本文关键字:Linq | 更新日期: 2023-09-27 18:33:48

Linq 非常强大,但有时我会发现自己急于进行扩展,后来我想知道我是否可以使用本机方法做到这一点。

那么,是否可以在不使用扩展的情况下实现以下内容?

/// <summary>
/// Removes duplicates that are immediately clustered together.
/// </summary>
public static IEnumerable<TData> DistinctLocal<TData>(this IEnumerable<TData> enumerable)
{
    bool yielded = false;
    TData last = default(TData);
    foreach (var item in enumerable)
    {
        if (yielded == false || last.Equals(item) == false)
        {
            last = item;
            yielded = true;
            yield return item;
        }
    }
}

Linq - 本地不同

以下是在普通 LINQ 中完成此操作的方法:

int[] source = new[] { 3, 6, 1, 8, 4, 1, 1, 1, 7, 4, 2, 2 };
var result = source.Where((x, i) => i == 0 || !x.Equals(source.ElementAt(i - 1)));

但是,仅当基础序列实现用于处理ElementAt调用的高效索引器时,才应使用此代码,最好是在 O(1) 时间内。这通常适用于IList<T>实现(如数组),但不适用于其他集合(如 LinkedList<T> )。

此外,如果您需要定期使用此功能,定义扩展方法并没有错,这比将此代码(或任何等效代码)分散到处更易于维护。我个人更喜欢使用您自己的扩展方法来避免非索引集合的性能问题的风险。

没有内置方法可以为您提供所需的功能,但显然您可以仅使用 LINQ 和一些黑客代码拼凑出解决方案。

但是:具有良好描述性名称的扩展方法将远远优于(ab)使用内置方法或功能来为您提供此名称。我的建议:使用扩展方法

但是,这里有一种非扩展方法黑客方法来获得相同的结果,您可以在 LINQPad 中对此进行测试:

void Main()
{
    var source = new[] { 1, 2, 3, 3, 2, 2, 3, 3, 1, 3, 1, 1 };
    int? prev = null;
    (from value in source
     where !prev.HasValue || prev.Value != value
     let dummy = prev = value
     select value).Dump();
}
您可以使用

Aggregate

source.Aggregate(new List<YourType>(), 
     (items, current) => 
     {
        if (!items.Any() || items.Last() != current)
            items.Add(current);
        return items;
     });

但显然它会消耗你的序列,所以你会失去懒惰......