Расширение IEnumerable's Select для включения источника в селектор - PullRequest
1 голос
/ 24 сентября 2019

Одна из перегрузок IEnumerable:

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

В селекторе я хочу включить источник.Я знаю, что это звучит нелогично, потому что вы изначально предоставляете источник для выбора, но в 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 значения.Просто текущий объект и индекс.Я хочу, чтобы он включал источник.

Я не хочу сначала создавать список отдельно, а затем делать .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(), поэтому индекс не будет полезен, так как мы не знаем, каким будет последний индекс, в отличие от нуля, являющегося первым.Отсюда моя потребность в том, чтобы источник был передан обратно.

Ответы [ 2 ]

2 голосов
/ 24 сентября 2019

Это должно работать:

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++;   
        }
}
2 голосов
/ 24 сентября 2019

Это должно сделать это:

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