2010-09-29 20 views
10

me gustaría evitar el bucleSeparar una cadena en lista <string> con LINQ

tengo esto:

string s = "AAAA,12,BBBB,34,CCCCC,56"; 

Con LINQ, me gustaría tener 2 Lista

En la primera: AAAA, BBBB y CCCCC

en el segundo: 12,34 y 56

no se basa en num eric o no numérico.

Gracias,

+1

¿Cuál es la división de la cadena basada en? Posición en la lista, número de caracteres, etc.? –

+0

Sí, es la posición en la lista –

+2

'Me gustaría evitar el bucle '¿Te das cuenta de que cualquier solución de LINQ que elijas, de hecho, usará al menos un bucle? –

Respuesta

29

Puede utilizar

var str = "AAAA,12,BBBB,34,CCCCC,56"; 

var spl = str.Split(','); 
var l1 = spl.Where((x, y) => y % 2 == 0).ToList(); 
var l2 = spl.Where((x, y) => y % 2 == 1).ToList(); 

Esto va a comprobar si el índice es par o impar.

1
+0

Si bien este enlace puede responder a la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace de referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia. - [De la crítica] (/ review/low-quality-posts/18997612) –

6

Dado que la regla es que desea cada segunda cadena en una lista y los otros en otra lista, puede hacer algo como esto:

 string s = "AAAA,12,BBBB,34,CCCCC,56"; 

     var parts = s.Split(','); 

     var first = parts.Where((p, i) => i % 2 == 0); 
     var second = parts.Where((p, i) => i % 2 == 1); 
2

no estoy seguro exactamente lo que su objetivo final es, pero se puede intentar esto:

var strings = s.Split(',').Where((s,p) => p % 2 == 0) 
-1

Si la lista no está ordenada con cada segundo que es un número que podía hacer algo g como esto

var stringList = "AAAA,12,BBBB,34,CCCCC,56".Split(','); 

var intsAsStrings = stringList.Where(
     (x) => 
     { 
      int i; 
      return int.TryParse(x, out i); 
     }).ToList(); 

var strings = stringList.Where(x => !intsAsStrings.Contains(x)).ToList(); 
+0

¿Por qué no utilizar simplemente Except en lugar de eso Where (x =>! IntsAsStrings.Contains (x))? Además, esto no es lo que quería el autor de la pregunta. – sloth

+0

No sabía el método Except, agradable. – Xorandor

1

Aquí está el filtro IsNumeric y no numérico para los interesados ​​... me doy cuenta de que no es necesaria

string x = "AAAA,12,BBBB,34,CCCCC,56"; 

Regex _isNumber = new Regex(@"^\d+$"); 

string[] y = x.Split(',') .Where(a => _isNumber.IsMatch(a)).ToArray(); 
string[] z =x.Split(',') .Where(a => !_isNumber.IsMatch(a)).ToArray(); 
8

Permite utilizar Aggregate para el gusto de hacerlo (y también, para demostrar esto se puede hacer como una única expresión):

"AAAA,12,BBBB,34,CCCC,56".Split(',').Aggregate(
    new { Uneven = new List<string>(), Even = new List<string>() }, 
    (seed, s) => { 
     if (seed.Uneven.Count > seed.Even.Count) 
      seed.Even.Add(s); 
     else 
      seed.Uneven.Add(s); 
     return seed; 
    }); 

según LINQPad, el resultado es la siguiente: alt text

Por supuesto que probablemente no lo haría de esta manera, ya que es algo difícil de leer. Y la prueba para la cual lista para anexar es, bueno, no es bueno.

Pero al menos ahora tenemos otro ejemplo de lambda declaraciones - normalmente la literatura LINQ intenta olvidarlas (probablemente porque no funcionarán con SQL o cualquier otro programa que utilice árboles de expresiones).

Una ventaja de este método en comparación con las soluciones de limpieza anteriores es que esto solo hace que una pase por la lista. Sin embargo, dado que estamos dividiendo una cadena, trataría de optimizar en otro lugar;) ¿No sería genial un IEnumerable<string> Split(this string self, string boundary)?

+0

Eh, genial. Difícilmente real, pero genial. –

+0

De alguna manera parece un extraño abuso de 'Agregado' si la función del acumulador modifica el parámetro fuente. Se siente como seguir la letra de la programación funcional mientras se contradice el espíritu. ¿Soy el único que piensa eso? – Niki

+0

@nikie con "parámetro fuente" quiere decir 'TSource' (no modificado) o' TAccumulate' (modificado, ¿pero no es siempre el caso?) –

1

puede agrupar de la posición y la extrat le listas de grupo, así:

 public IEnumerable<IEnumerable<T>> ToLists<T>(IEnumerable<T> sequence) 
     { 
      var res = sequence.Select((item, position) => new { Item = item, Position = position }) 
           .GroupBy(pair => pair.Position % 2 == 0,pair => pair.Item); 
      return from grouping in res 
        select grouping; 
     } 

Si desea que las listas sean de diferentes tipos que se pueden repetir el resultado. Cuál es por qué el tipo de devolución no es IEnumerable> pero IEnumerable>. El uso de ToList repetirá la secuencia, pero si desea realizar alguna acción en cada elemento, también podría fusionar esas acciones, realice una iteración a través del sequnce superflourious

0

Tan divertido, sin efectos secundarios ni llamadas a métodos.

"TesteDessaBudega".Aggregate(new List<List<char>>(), 
(l, c) => char.IsUpper(c) ? 
    l.Union(
     new List<List<char>>(){ 
      new List<char>(){c} 
     } 
    ).ToList() : 
    l.Take(l.Count - 1).Union(
     new List<List<char>>(){ 
      l.Last().Union(
       new List<char>(){c} 
      ).ToList() 
     } 
    ).ToList() 
) 

Oh, en vbnet solo para más diversión.

"TesteDessaBudega".Aggregate(New List(Of List(Of Char))(), 
Function(l, c) If(Char.IsUpper(c), 
    l.Union(
     New List(Of List(Of Char))(New List(Of Char)(){ 
      New List(Of Char)(New Char(){c}) 
     }) 
    ).ToList(), 
    l.Take(l.Count - 1).Union(
     New List(Of List(Of Char))(New List(Of Char)(){ 
      l.Last().Union(
       New List(Of Char)(New Char(){c}) 
      ).ToList() 
     }) 
    ).ToList() 
)) 

linqresult

+1

Realmente no estoy seguro de cómo esto tiene alguna relevancia para la pregunta. Tengo la sensación de que estás respondiendo una pregunta diferente. – btlog

Cuestiones relacionadas