首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >作为IEnumerable扩展的TopN

作为IEnumerable扩展的TopN
EN

Stack Overflow用户
提问于 2016-03-19 02:26:20
回答 2查看 57关注 0票数 0

我正在尝试添加一个通用的TopN IEnumerable<T>扩展。

如果参数为正,则它与Take()相同,但如果参数为负,则应与Take()相同,但随后立即生成与Take()的最后一个值匹配的序列值。(与SQL TOP n WITH TIES相同)

这是我目前拥有的代码:

代码语言:javascript
复制
public static class Test
{
    public static IEnumerable<TSource> TopN<TSource>(this IEnumerable<TSource> source, int topN)
    {
        return TopN(source, topN, (v1, v2) => v1.Equals(v2));
    }

    public static IEnumerable<TSource> TopN<TSource>(this IEnumerable<TSource> source, int topN, Func<TSource, TSource, bool> comparer)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (comparer == null) throw new ArgumentNullException(nameof(comparer));

        return topN >= 0
            ? source.Take(topN)
            : TopNWithTiesIterator(source, -topN, comparer);
    }

    static IEnumerable<TSource> TopNWithTiesIterator<TSource>(this IEnumerable<TSource> source, int topN, Func<TSource, TSource, bool> comparer)
    {
        var lastItem = default(TSource);

        foreach (var item in source)
        {
            if (topN-- > 0 || comparer(item, lastItem))
            {
                lastItem = item;

                yield return item;
            }
            else
            {
                yield break;
            }
        }
    }
}

下面是我尝试过的实际用法和其他一些快速测试的示例:

代码语言:javascript
复制
        if (TopN != 0)
        {
            var values = new[] { 1, 2, 2, 3 };
            Debug.Assert(!values.TopN(0).Any());
            Debug.Assert(!values.TopN(0, (v1, v2) => v1 == v2).Any());

            Debug.Assert(values.TopN(1, (v1, v2) => v1 == v2).Count() == 1);
            Debug.Assert(values.TopN(-1, (v1, v2) => v1 == v2).Count() == 1);

            Debug.Assert(values.TopN(2, (v1, v2) => v1 == v2).Count() == 2);
            Debug.Assert(values.TopN(-2, (v1, v2) => v1 == v2).Count() == 3);

            Debug.Assert(values.TopN(2).Count() == 2);
            Debug.Assert(values.TopN(-2).Count() == 3);

            // This is how I really want to use it
            summaries = summaries.TopN(TopN, (v1, v2) => v1.ClientValue + v1.AdviserValue == v2.ClientValue + v2.AdviserValue);
        }

我的问题是,使用Func<TSource, TSource, bool>作为比较器是否正确。

我应该使用IEqualityComparer<T>还是IEquatable<<T>或其他什么?

EN

回答 2

Stack Overflow用户

发布于 2016-03-19 03:56:54

默认和预期行为应为:

  • 如果没有提供IEqualityComparer<T>,您的方法应该检查TSource是否实现了IEquatable<T>并使用IEquatable<T>.Equals(T)。否则,它应该使用Object.Equals.
  • If提供的谓词,然后使用它。
  • 如果提供了谓词来模拟IEqualityComparer<T>行为,则使用它而不是IEqualityComparer<T>
票数 1
EN

Stack Overflow用户

发布于 2016-03-19 03:03:02

Func<TSource, TSource, bool>IEqualityComparer<T>之间没有选择。您在(v1, v2) => v1.Equals(v2)中使用的是默认对象的Equals比较器。

因此,这取决于您是否希望通过Func<>或直接作为可选方法参数提供自定义比较器。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36091731

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档