扩展 IEnumerable 的 Select 以在选择器中包含源

Extension of IEnumerable's Select to include the source in the selector

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参数没有return3个值。只是当前对象和索引。我希望它包含来源。

我不想先单独创建列表,然后再对其执行 .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() 因此索引不会有用,因为我们不知道最后一个索引是什么,而不是第一个为零。因此我需要传回源代码。

应该这样做:

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<TSource, int, IEnumerable<TSource>, TResult>,不是Func<TSource, int, TResult, IEnumerable<TSource>>.

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

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

这应该有效:

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