Лямбда-выражение как параметр функции

#c#

#c#

Вопрос:

У меня есть следующий код

 List<int> GetIndices<T>(List<T> list, ?????? condition
{
    var result =
            list
                .Select((p, index) => index)
                .Where(condition);

    return result.ToList();
}
  

И я хотел бы назвать это как GetIndices(someList, (p, index) => (someList[index].Height < someList[index - 1].Height))

Какой правильный тип condition ?

Ответ №1:

В вашем коде ошибка: Where ожидается делегат, который возвращает bool значение и имеет тип элемента списка в качестве входных данных.

 var result = list
   .Select((p, index) => index) // projects the element to it's index (of type int)
   .Where(condition);           // => expects Func<int, bool>
  

Итак, вам понадобится Func<int,bool>

Однако, исходя из вашей спецификации, я думаю, вы хотите Func<T,int,bool> , что означает, что вам нужно переписать свою реализацию GetIndices как

 var result = list
   .Select((p, index) => new {p, index}) 
   .Where(x => condition(x.p, x.index))
   .Select(x => x.index);  
  

Комментарии:

1. Enumerable.Where Метод также имеет перегрузку, принимающую функцию<T, int, bool> .

2. @Tesserex: но тогда вы теряете исходный индекс, я думаю

Ответ №2:

 Func<T, bool>
  

Должно сработать, но вам придется немного изменить свой лямбда-код, потому что вы не можете передать индекс (если вы хотите использовать condition в Where предложении). Вы могли бы легко изменить свой лямбда на:

 p => someList[someList.IndexOf(p).Height < someList[someList.IndexOf(p)-1].Height
  

Для дальнейшего использования документация MSDN по методам расширения будет отличной, как только вы научитесь ее читать (эта часть займет немного времени):

MSDN — Перечислимый.Где метод

Поскольку это метод расширения, первым параметром ( IEnumerable<TSource> ) является коллекция, для которой вы вызываете метод ( List<T> в вашем случае).

Второй параметр — это то, что вам нужно сопоставить. Поскольку документация требует Func<TSource, bool> и TSource является T в вашем случае…вы получаете Func<T, bool>

Комментарии:

1. это должно сработать, с небольшой оговоркой, что, если someList значение велико, вы, возможно, создали здесь проблему с производительностью ( IndexOf это операция O (N)))

Ответ №3:

Как понял джероен, вам нужно записать исходный индекс. Funct<T,int,bool> Условие, которое вы передаете, должно содержать информацию только об элементе и его индексе, а не об анонимном типе, созданном в запросе, поэтому передаваемое условие немного меняется. Он также должен обрабатывать ситуацию, когда индекс == 0 и, следовательно, нет предыдущих элементов (индекс — 1).

 class Program {
    static void Main( string[] args ) {
        var items = Item.GetItems();
        // mind the case where index == 0 so you don't grab an item out of bounds
        var ind = GetIndices( items,
            ( p, index ) => ( h.index == 0 ) ? false : p.Height < items[ index - 1 ].Height );
    }

    static List<int> GetIndices<T>( List<T> list, Func<T, int, bool> condition ) {
        var res = list
            .Select( ( item, index ) => new { item, index } ) // capture original index
            .Where( h => condition( h.item, h.index ) )
            .Select( h => h.index ); // reduce to the index again
        return res.ToList();
    }
}

class Item {
    public int Height {
        get;
        set;
    }
    public Item( int h ) {
        Height = h;
    }
    static public List<Item> GetItems() {
        return new List<Item>( new[]{
                     new Item(1),
                     new Item(4),
                     new Item(2),
                     new Item(5)
        } );
    }
}
  

Комментарии:

1. Это выглядит чрезмерно сложным. Может быть, мне лучше не использовать linq?

2. Да, это можно было бы сделать проще, возможно, даже с помощью LINQ. Если вы используете Where() first, оно примет Func<T,int,bool> и передаст индекс. В for цикле также нет ничего плохого, и Func<> условие все еще можно передать и использовать.

Ответ №4:

Попробуйте Func<bool> .

Или, скорее, вариант с правильным количеством входных параметров.