扩展IEnumerable的Select,以将源包括在选择器中

时间:2019-09-24 05:58:33

标签: c# linq select ienumerable class-extensions

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的选择器参数未返回3个值。只是当前对象和索引。我希望它包含来源。

我不想先单独创建列表,然后再对其进行处理。

这是我对扩展程序所做的努力;我不确定如何实现。

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(),因此索引将无用,因为我们不知道最后一个索引是什么,而不是首先是零。因此,我需要将源传递回去。

2 个答案:

答案 0 :(得分:2)

这应该做到:

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

答案 1 :(得分: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++;   
        }
}