2009-03-24 7 views
5

¿Por qué no puedo hacer algo como esto?Usar declaraciones lambda condicional con un foreach Acción en una lista

Si tengo un List<String> myList poblada de artículos, yo quiero ser capaz de actuar en cada miembro de una manera condicional, así:

myList.ForEach(a => { if (a.Trim().Length == 0) a = "0.0"; }) 

Pero esto no se compilará. ¿Supongo que tiene algo que ver con perder un valor de retorno?

Im tratando de preparar una lista de cadenas para la conversión a dobles, y quiero que los elementos vacíos muestren '0.0' para que pueda convertir toda la lista de una vez.

+1

le recomiendo que visite www.lambdaexpression.net – Delashmate

Respuesta

6

ForEach is not mutable, no cambia la estructura de datos de ninguna manera.

Puede:

  1. manija del bucle mismo, con un índice
  2. producir una nueva lista, utilizando .Elija y .ToList (siempre que estés utilizando .NET 3.5)

Ejemplo de # 1:

for (Int32 index = 0; index < myList.Count; index++) 
    if (myList[index].Trim().Length == 0) 
     myList[index] = "0.0"; 

Con .NET 3.5 y Linq:

myList = (from a in myList 
      select (a.Trim().Length == 0) ? "0.0" : a).ToList(); 

Con .NET 3.5, no se utiliza la sintaxis de LINQ, pero utilizando el código de LINQ:

myList = myList.Select(a => (a.Trim().Length == 0) ? "0.0" : a).ToList(); 

Editar: Si se quiere producir una nueva lista de dobles, también se puede hacer eso en una sola vez usando LINQ:

List<Double> myDoubleList = 
    (from a in myList 
    select (a.Trim().Length == 0 ? "0" : a) into d 
    select Double.Parse(d)).ToList(); 

Tenga en cuenta que el uso de "0.0" en lugar de sólo "0" se basa en la coma decimal es el punto final c haracter. En mi sistema no lo es, así que lo reemplazó con sólo "0", pero de una manera más apropiada sería cambiar la llamada a Double.Parse tomar un formato numérico explícito, como esto:

List<Double> myDoubleList = 
    (from a in myList 
    select (a.Trim().Length == 0 ? "0.0" : a) into d 
    select Double.Parse(d, CultureInfo.InvariantCulture)).ToList(); 
+0

Hmmm bien, ¿hay algún método de extensión que le permitirá actuar sobre cada elemento de la lista? – Alex

+0

No es que yo sepa, y lo dudo, la mayoría de los métodos Linq están construidos en un estilo funcional, que no permite cambiar la entrada de ninguna manera. –

+0

Gracias por la excelente explicación. – Alex

4

lo que queremos es posiblemente:

public static void MutateEach(this IList<T> list, Func<T, T> mutator) 
{ 
    int count = list.Count; 
    for (int n = 0; n < count; n++) 
     list[n] = mutator(list[n]); 
} 

lo que permitiría:

myList.MutateEach(a => (a.Trim().Length == 0) ? "0.0" : a); 

Sólo hay que poner el método MutateEach en una clase estática pública de su propio y asegúrese de que haya una directiva using que lo encontrará.

Si vale la pena definir algo como esto depende de la frecuencia con la que lo usaría. Tenga en cuenta que tiene que ser una extensión en IList en lugar de IEnumerable, por lo que podemos realizar las actualizaciones, lo que hace que sea menos aplicable.

+0

+1 para nombrar, lo que haría de esto una buena extensión. –

+1

Ustedes son fantásticos. Aprendo algo cada vez que hago una pregunta en este sitio. – Alex

0

@ daniel-earwicker's MutateEach La solución de extensión es una buena solución.


Aunque, para el retorno de una nueva List, usted tiene la opción de utilizar List.ConvertAll<TTo>(Converter<TFrom,TTo>(Func<TFrom, TTo>)), que ha estado presente desde .NET 2.0.

No es Linq, o Lambda.

List<String> nodeStringList = new List<String>(new String[] { "", "0.5 ", " 1.1"}); 

nodeStringList = nodeStringList.ConvertAll<String>((c) => (c.Value.Trim().Length != 0) ? c.Value.Trim() : "0.0"); 

MSDN Reference - List.ConvertAll

Cuestiones relacionadas