【问题标题】:Extension of IEnumerable's Select to include the source in the selector扩展 IEnumerable 的 Select 以将源包含在选择器中
【发布时间】:2019-09-24 05:58:33
【问题描述】:

IEnumerable 的重载之一是:

public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector);

我希望在选择器中包含源代码。我知道这听起来违反直觉,因为您首先提供了 Select 的源代码,但 JavaScript 也有类似的东西。我想在这里快速使用它:

var greetings = new List<string> { "John", "Keith", "Sarah", "Matt" }.Select((name, index, source) => {
    if (name == source.First())
        return $"{name} (Todays Winner)";
    return name;
});

上面会报错,因为Select的selector参数没有返回3个值。只是当前对象和索引。我希望它包含源代码。

我不想先单独创建列表,然后对它执行 .first。

这是我在扩展方面的进展;我不确定如何实现它。

public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult, IEnumerable<TSource>> selector)
{
    //not sure what to put in here, must be missing something simple ;(
}

更新

上述情况只是一个虚构的例子。我的实际情况需要使用.Last() 而不是.First(),所以索引不会有用,因为我们不知道最后一个索引是什么,而不是第一个索引是零。因此我需要将源传回。

【问题讨论】:

    标签: c# linq select ienumerable class-extensions


    【解决方案1】:

    应该这样做:

    public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TSource>, TResult> selector)
    {
        using (var enumerator = source.GetEnumerator()) {
            for (var i = 0 ; enumerator.MoveNext() ; i++) {
                yield return selector(enumerator.Current, i, source);
            }
        }
    }
    

    请注意,您为selector 参数编写了错误的类型。应该是Func&lt;TSource, int, IEnumerable&lt;TSource&gt;, TResult&gt;,而不是Func&lt;TSource, int, TResult, IEnumerable&lt;TSource&gt;&gt;

    如果你只想检查一个元素是否是第一个,为什么不检查index == 0

    var greetings = new List<string> { "John", "Keith", "Sarah", "Matt" }.Select((name, index, source) => {
        if (index == 0)
            return $"{name} (Todays Winner)";
        return name;
    });
    

    【讨论】:

    • 检查索引为零是对的,但我的真实代码需要 Last()。在我的示例中应该使用 Last 。让我尝试使用产量。第一次使用。
    • 是的,粗略地说,TResult 作为返回类型排在最后,哈哈。干杯。
    • 是否有可能与foreach 类似?也就是说,在每次迭代中以某种方式传回源代码的扩展
    • @pnizzle 您的意思类似于其他答案中显示的方法吗?
    • @pnizzle 经过一番试验,我发现你需要使用自定义列表类来做到这一点。您只需要使该列表实现IEnumerable&lt;(T, CustomList&lt;T&gt;)&gt;
    【解决方案2】:

    这应该可行:

    public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TSource>, TResult> selector)
    {
            int index = 0;
            foreach(var item in source)
            {
                yield return selector(item, index, source);
                index++;   
            }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-04-01
      • 2023-03-18
      • 2016-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-13
      相关资源
      最近更新 更多