2011-05-11 22 views
6

Tengo el siguiente códigoexpresión Lambda como parámetro de la función

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

    return result.ToList(); 
} 

Y me gustaría llamarlo como GetIndices(someList, (p, index) => (someList[index].Height < someList[index - 1].Height))

¿Cuál es el tipo correcto de condition?

Respuesta

1
Func<T, bool> 

debe hacer el truco pero vas a tener que modificar lambda un poco porque no se puede pasar el índice (si desea utilizar condición de la cláusula Where). Desde aquí se puede cambiar de lambda para:

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

Para referencia futura, la documentación de MSDN para los métodos de extensión es grande una vez que aprenda cómo leerlo (la parte toma un poco):

MSDN - Enumerable.Where Method

Dado que este es un método de extensión, el primer parámetro (IEnumerable<TSource>) es la colección que llama al método (List<T> en su caso).

El segundo parámetro es lo que necesita para hacer coincidir. Dado que la documentación exige Func<TSource, bool>TSource y es T en su caso ... se obtiene Func<T, bool>

+0

esto debería funcionar, con la pequeña salvedad de que si 'someList' es grande que podría haber introducido un problema de rendimiento aquí (' IndexOf' es un O (N) la operación) – jeroenh

4

Hay un error en el código: Where espera un delegado que devuelve un valor bool y tiene el tipo de lista de elementos como entrada.

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

lo que tendría que Func<int,bool>

Sin embargo, a partir de su especificación Creo que quieres Func<T,int,bool>, lo que significa que tiene que volver a escribir su implementación de GetIndices como

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

El método 'Enumerable.Where' también tiene una sobrecarga que acepta un Func . – Tesserex

+0

@Tesserex: pero luego pierdes el índice original, creo que – jeroenh

1

Como jeroenh se dio cuenta, se necesidad de capturar el índice original. La condición Funct<T,int,bool> que pase solo necesita conocer el elemento y su índice, no el tipo anónimo creado en la consulta, por lo que la condición aprobada cambia un poco. También debe manejar la situación donde el índice == 0 y, por lo tanto, no hay elementos precedentes (índice - 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) 
     }); 
    } 
} 
+0

Parece demasiado complicado. ¿Será mejor que no use linq? – kasperhj

+0

Sí, podría hacerse más simple, tal vez incluso con LINQ. Si usa 'Where()' primero, aceptará un 'Func ' y pasará el índice. No hay nada malo con un bucle 'for', tampoco, y la condición' Func <> 'aún puede pasarse y usarse. –

Cuestiones relacionadas