6

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;
        }
    }
}
4

3 回答 3

4

这是在普通 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>.

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

于 2013-10-04T09:37:23.280 回答
2

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

但是:具有良好描述性名称的扩展方法将远远好于(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();
}
于 2013-10-04T09:31:02.597 回答
2

你可以使用Aggregate

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

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

于 2013-10-04T09:39:19.323 回答