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