objetos concatenar caracteres cadenas linq string-concatenation

caracteres - Usando LINQ para concatenar cadenas



concatenar objetos c# (17)

¿Cuál es la forma más eficiente de escribir la vieja escuela?

StringBuilder sb = new StringBuilder(); if (strings.Count > 0) { foreach (string s in strings) { sb.Append(s + ", "); } sb.Remove(sb.Length - 2, 2); } return sb.ToString();

... en LINQ?


¿Has mirado el método de extensión Agregado?

var sa = (new[] { "yabba", "dabba", "doo" }).Aggregate((a,b) => a + "," + b);


¿Por qué usar Linq?

string[] s = {"foo", "bar", "baz"}; Console.WriteLine(String.Join(", ", s));

Eso funciona perfectamente y acepta cualquier IEnumerable<string> por lo que recuerdo. No es necesario Aggregate nada aquí, lo cual es mucho más lento.


Aquí está el enfoque de Unir / Linq combinado que decidí después de ver las otras respuestas y los problemas abordados en una pregunta similar (es decir, que el Agregado y el Concatenado fallan con 0 elementos).

string Result = String.Join(",", split.Select(s => s.Name));

o (si s no es una cadena)

string Result = String.Join(",", split.Select(s => s.ToString()));

  • Sencillo
  • Fácil de leer y entender
  • trabaja para elementos genéricos
  • Permite usar objetos o propiedades de objetos.
  • Maneja el caso de los elementos de longitud 0.
  • podría ser usado con filtrado Linq adicional
  • Funciona bien (al menos en mi experiencia)
  • no requiere la creación (manual) de un objeto adicional (por ejemplo, StringBuilder ) para implementar

Y, por supuesto, Join se ocupa de la molesta coma final que a veces se cuela en otros enfoques ( for , foreach ), por lo que estaba buscando una solución Linq en primer lugar.


Aquí está usando LINQ puro como una sola expresión:

static string StringJoin(string sep, IEnumerable<string> strings) { return strings .Skip(1) .Aggregate( new StringBuilder().Append(strings.FirstOrDefault() ?? ""), (sb, x) => sb.Append(sep).Append(x)); }

¡Y es bastante rápido!


Ejemplo real de mi código:

return selected.Select(query => query.Name).Aggregate((a, b) => a + ", " + b);

Una consulta es un objeto que tiene una propiedad de nombre que es una cadena, y quiero los nombres de todas las consultas en la lista seleccionada, separados por comas.


Hace un blog sobre esto hace un tiempo, lo que hice para ser exactamente lo que estás buscando:

http://ondevelopment.blogspot.com/2009/02/string-concatenation-made-easy.html

En la publicación del blog, describe cómo implementar métodos de extensión que funcionen en IEnumerable y se llamen Concatenate, esto te permitirá escribir cosas como:

var sequence = new string[] { "foo", "bar" }; string result = sequence.Concatenate();

O cosas más elaboradas como:

var methodNames = typeof(IFoo).GetMethods().Select(x => x.Name); string result = methodNames.Concatenate(", ");


Hay varias respuestas alternativas en esta pregunta anterior , que sin duda apuntaba a una matriz de enteros como origen, pero recibió respuestas generalizadas.


Hice lo siguiente rápido y sucio al analizar un archivo de registro IIS usando linq, funcionó bastante bien en 1 millón de líneas (15 segundos), aunque obtuve un error de memoria al intentar 2 millones de líneas.

static void Main(string[] args) { Debug.WriteLine(DateTime.Now.ToString() + " entering main"); // USED THIS DOS COMMAND TO GET ALL THE DAILY FILES INTO A SINGLE FILE: copy *.log target.log string[] lines = File.ReadAllLines(@"C:/Log File Analysis/12-8 E5.log"); Debug.WriteLine(lines.Count().ToString()); string[] a = lines.Where(x => !x.StartsWith("#Software:") && !x.StartsWith("#Version:") && !x.StartsWith("#Date:") && !x.StartsWith("#Fields:") && !x.Contains("_vti_") && !x.Contains("/c$") && !x.Contains("/favicon.ico") && !x.Contains("/ - 80") ).ToArray(); Debug.WriteLine(a.Count().ToString()); string[] b = a .Select(l => l.Split('' '')) .Select(words => string.Join(",", words)) .ToArray() ; System.IO.File.WriteAllLines(@"C:/Log File Analysis/12-8 E5.csv", b); Debug.WriteLine(DateTime.Now.ToString() + " leaving main"); }

La verdadera razón por la que usé linq fue para un Distinct () que necesitaba anteriormente:

string[] b = a .Select(l => l.Split('' '')) .Where(l => l.Length > 11) .Select(words => string.Format("{0},{1}", words[6].ToUpper(), // virtual dir / service words[10]) // client ip ).Distinct().ToArray() ;


Por '' super-cool LINQ way '' podría estar hablando de la forma en que LINQ hace que la programación funcional sea mucho más aceptable con el uso de métodos de extensión. Quiero decir, el azúcar sintáctico que permite que las funciones se encadenen de manera visualmente lineal (una tras otra) en lugar de anidar (una dentro de la otra). Por ejemplo:

int totalEven = Enumerable.Sum(Enumerable.Where(myInts, i => i % 2 == 0));

se puede escribir así:

int totalEven = myInts.Where(i => i % 2 == 0).Sum();

Puedes ver cómo el segundo ejemplo es más fácil de leer. También puede ver cómo se pueden agregar más funciones con menos problemas de sangrado o el parén de cierre Lispy que aparece al final de la expresión.

Muchas de las otras respuestas afirman que String.Join es el camino a seguir porque es la más rápida o sencilla de leer. Pero si tomas mi interpretación de la " forma String.Join estupenda ", entonces la respuesta es usar String.Join pero la tienes envuelta en un método de extensión de estilo LINQ que te permitirá encadenar tus funciones de una manera visualmente agradable. Entonces, si quieres escribir sa.Concatenate(", ") solo necesitas crear algo como esto:

public static class EnumerableStringExtensions { public static string Concatenate(this IEnumerable<string> strings, string separator) { return String.Join(separator, strings); } }

Esto proporcionará un código que es tan eficaz como la llamada directa (al menos en términos de complejidad de algoritmo) y en algunos casos puede hacer que el código sea más legible (dependiendo del contexto) especialmente si otro código en el bloque está usando el estilo de función encadenada .


Puedes combinar LINQ y string.join() bastante efectiva. Aquí estoy eliminando un elemento de una cadena. Hay mejores formas de hacer esto también, pero aquí está:

filterset = String.Join(",", filterset.Split('','') .Where(f => mycomplicatedMatch(f,paramToMatch)) );


Puedes usar StringBuilder en Aggregate :

List<string> strings = new List<string>() { "one", "two", "three" }; StringBuilder sb = strings .Select(s => s) .Aggregate(new StringBuilder(), (ag, n) => ag.Append(n).Append(", ")); if (sb.Length > 0) { sb.Remove(sb.Length - 2, 2); } Console.WriteLine(sb.ToString());

(La Select está ahí solo para mostrar que puedes hacer más cosas de LINQ).


Siempre uso el método de extensión:

public static string JoinAsString<T>(this IEnumerable<T> input, string seperator) { var ar = input.Select(i => i.ToString()).ToArray(); return string.Join(seperator, ar); }


Un montón de opciones aquí. Puedes usar LINQ y un StringBuilder para obtener el rendimiento, así:

StringBuilder builder = new StringBuilder(); List<string> MyList = new List<string>() {"one","two","three"}; MyList.ForEach(w => builder.Append(builder.Length > 0 ? ", " + w : w)); return builder.ToString();


Utilice consultas agregadas como esta:

string[] words = { "one", "two", "three" }; var res = words.Aggregate((current, next) => current + ", " + next); Console.WriteLine(res);

Esto produce:

one, two, three

Un agregado es una función que toma una colección de valores y devuelve un valor escalar. Los ejemplos de T-SQL incluyen min, max y sum. Tanto VB como C # tienen soporte para agregados. Tanto VB como C # admiten agregados como métodos de extensión. Usando la notación de puntos, uno simplemente llama a un método en un objeto IEnumerable .

Recuerde que las consultas agregadas se ejecutan inmediatamente.

http://msdn.microsoft.com/en-us/library/bb386914.aspx

Debido a que esto no utiliza un StringBuilder , tendrá un rendimiento horrible para secuencias muy largas.


Voy a hacer trampa un poco y lanzar una nueva respuesta a esto que parece resumir lo mejor de todo aquí en lugar de pegarlo dentro de un comentario.

Así que uno puede alinear esto:

List<string> strings = new List<string>() { "one", "two", "three" }; string concat = strings .Aggregate(new StringBuilder("/a"), (current, next) => current.Append(", ").Append(next)) .ToString() .Replace("/a, ",string.Empty);

Edición: primero querrá verificar si hay un enumerable vacío o agregar un .Replace("/a",string.Empty); hasta el final de la expresión. Supongo que podría haber estado tratando de ser un poco demasiado inteligente.

La respuesta de @ a.friend puede ser un poco más eficaz, no estoy seguro de lo que Reemplace hace debajo del capó en comparación con Quitar. La única otra advertencia: si por alguna razón quisiera concatear cadenas que terminaron en / a, perdería sus separadores ... Lo encuentro poco probable. Si ese es el caso, tienes otros personajes de fantasía para elegir.


datos de rendimiento rápidos para el caso StringBuilder vs Seleccionar y agregar más de 3000 elementos:

Prueba unitaria - Duración (segundos)
LINQ_StringBuilder - 0.0036644
LINQ_Seleccionar. Agregado - 1.8012535

[TestMethod()] public void LINQ_StringBuilder() { IList<int> ints = new List<int>(); for (int i = 0; i < 3000;i++ ) { ints.Add(i); } StringBuilder idString = new StringBuilder(); foreach (int id in ints) { idString.Append(id + ", "); } } [TestMethod()] public void LINQ_SELECT() { IList<int> ints = new List<int>(); for (int i = 0; i < 3000; i++) { ints.Add(i); } string ids = ints.Select(query => query.ToString()) .Aggregate((a, b) => a + ", " + b); }


return string.Join(", ", strings.ToArray());

En .Net 4, hay una nueva overload para string.Join que acepta IEnumerable<string> . El código se vería así:

return string.Join(", ", strings);