2012-01-04 7 views
20

Así que tengo una lista de cadenas que se parece a esto:Linq: Cómo llegar a durar segundos

var ls=new List<string>() 
    { 
     "100", 
     "101-102-1002", 
     "105-153-1532-1532", 
     "105-1854-45-198", 
     "180-95-45-200" 
    }; 

que desea obtener el último segundo de la cadena de la división. Así que mi salida se parece a esto:

null, 
102, 
1532, 
45, 
45 

tengo una solución para ello que tiene este aspecto:

ls.Select (l =>l.Split('-').Select ((s,i) =>new {s,i}) 
.OrderByDescending (x=>x.i).Skip(1).Take(1)) 

creo que esta solución podría ser complejo para esta tarea simple. Entonces mi pregunta es: ¿Alguno de ustedes tiene una solución más simple para este problema?

+2

El resultado es incorrecto o que no entiendo la pregunta: ¿No debería ser: nulo, 102,153,1235? –

+1

¡Su solución se ve bien para mí! – ColinE

+0

Sí, debería ser la penúltima cadena dividida. Si no hay segundo último, entonces debería devolver nulo. – Arion

Respuesta

31

Reverse encaja bien aquí:

ls.SelectMany(l =>l.Split('-').Reverse().Skip(1).Take(1).DefaultIfEmpty()) 

También uso SelectMany para transformar IEnumerable<IEnumerable<string>> a <IEnumerable<string>.

+1

El único problema con esta solución es que no obtendría 'nulo' cuando la longitud de la matriz dividida es menor que 2. Esto está más cerca, pero no es correcto, ya que escupe en blanco en lugar de 'nulo' ls.Seleccione (x => x .Split ('-'). Reverse(). Skip (1) .Take (1) .FirstOrDefault()). ToList(); – Anand

+0

@Anand Sí, gracias por la pista. Sin embargo, prefiero mi código LINQ para permanecer en la mónada LINQ. –

+0

@TimSchmelter No te entiendo. Si 'ls' está vacío, el resultado estará vacío. Si un elemento en 'ls' es demasiado corto y no tiene al menos 2 componentes, el resultado contendrá' null' en lugar de ese elemento. Sin embargo, este comportamiento puede parecer extraño, pero esto es lo que el autor quiere, ¿no es así? –

2
var ls = new List<string> { "100", "101-102-1002", "105-153-1532-1532", "12-1235-785" }; 
var result = ls.Select(x => 
{ 
    var tokens = x.Split('-'); 
    if (tokens.Length < 2) 
    { 
     return null; 
    } 
    return tokens[tokens.Length - 2]; 
}); 
12
 var ls = new List<string>() { "100", "101-102-1002", "105-153-1532-1532", "12-1235-785" }; 
     var result = from p in ls 
        let arr = p.Split('-') 
        select arr.Length < 2 ? null : arr[arr.Length - 2]; 

     foreach (var item in result) 
     { 
      Console.WriteLine(item); 
     } 



     Console.Read(); 
+0

Esta debería haber sido la respuesta. Es más rápido que el otro. – DanielCuadra

6
var ls = new List<string>(){"100","101-102-1002","105-153-1532-1532","12-1235-785"}; 

var result = from l in ls 
      let s = l.Split('-') 
      select s.ElementAtOrDefault(s.Length - 2); 
+0

No escupe 'nulo' cuando la longitud es menor a 2, en cambio FirstOrDefault escupe en blanco. – Anand

+0

@Anand, no estoy seguro de lo que quiere decir, devuelve 'null' para la primera entrada. –

6

Si tiene

var ls = new List<string>(...);

continuación

var result = ls.Reverse().Skip(1).Take(1);

debería funcionar.

0

En la sintaxis lambda:

var ls = new List<string>() { "100", "101-102-1002", "105-153-1532-1532", "12-1235-785" }; 

var result = ls.Select(x => new { split = x.Split('-') }).Select(y => y.split.LastOrDefault(z => z != y.split.LastOrDefault())); 
+0

Así que ya sabes, si resaltas el texto y presionas el botón "codificar", se formateará correctamente para que se muestre como un bloque de código para ti. He avanzado y enviado y edito esta vez. – Amicable

1

He creado una extensión basado en la respuesta de Pavel Gatilov anterior

public static TSource SecondLast<TSource>(this IEnumerable<TSource> source) 
{ 
      //from http://stackoverflow.com/questions/8724179/linq-how-to-get-second-last 
      return source.Reverse().Skip(1).Take(1).FirstOrDefault(); 
} 
Cuestiones relacionadas