concatenate - linq concatenar dos campos
Usar LINQ para concatenar cadenas (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í, que es mucho más lento.
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 Name que es una cadena, y quiero los nombres de todas las consultas en la lista seleccionada, separados por comas.
Use 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
Como esto no usa un StringBuilder
, tendrá un rendimiento horrible para secuencias muy largas.
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);
}
Muchas opciones aquí. Puede usar LINQ y un StringBuilder para que también obtenga el rendimiento de la siguiente manera:
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();
datos de rendimiento rápido para stingbuilder vs Select case más de 3000 elementos:
unidad de prueba Duración (segundos) LINQ_SELECT 00: 00: 01.8012535
LINQ_StringBuilder 00: 00: 00.0036644
[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);
}
Puede 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());
(El Select
está ahí solo para mostrar que puedes hacer más cosas de LINQ).
Hace un blog sobre esto hace un tiempo, lo que hice parece ser exactamente lo que estás buscando:
http://ondevelopment.blogspot.com/2009/02/string-concatenation-made-easy.html
En la publicación del blog describa cómo implementar métodos de extensión que funcionen en IEnumerable y se denominen Concatenat, esto le 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(", ");
return string.Join(", ", strings.ToArray());
En .Net 4, hay una nueva sobrecarga para la IEnumerable<string>
. string.Join
que acepta IEnumerable<string>
. El código se vería así:
return string.Join(", ", strings);
Puede combinar LINQ y string.join()
bastante eficacia. Aquí estoy quitando un artículo de una cadena. Hay mejores formas de hacerlo también, pero aquí está:
filterset = String.Join(",",
filterset.Split('','')
.Where(f => mycomplicatedMatch(f,paramToMatch))
);
Hice lo siguiente rápido y sucio al analizar un archivo de registro IIS usando linq, funcionó bastante bien 1 millón de líneas (15 segundos), aunque recibí un error de falta de memoria cuando probaba 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 utilicé linq fue para un Distintivo () que necesitaba antes:
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()
;
Aquí está utilizando pure LINQ como expresión única:
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 muy rápido!
Voy a hacer trampa un poco y arrojaré una nueva respuesta a esto que parece resumir lo mejor de todo aquí en lugar de meterlo dentro de un comentario.
Entonces puedes 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);
Editar: querrá verificar primero un enumerable vacío o agregar un .Replace("/a",string.Empty);
hasta el final de la expresión Supongo que podría haber estado intentando ser un poco inteligente.
La respuesta de @ a.friend podría ser un poco más efectiva, no estoy seguro de qué es lo que Replace hace en comparación con Remove. La única otra advertencia es que si alguna razón por la que quieres concat cadenas que terminaron en / a''s, perderías tus separadores ... Me parece poco probable. Si ese es el caso, tiene otros personajes elegantes para elegir.
Con "la manera LINQ super cool ", podría estar hablando de la forma en que LINQ hace que la programación funcional sea mucho más agradable con el uso de métodos de extensión. Quiero decir, el azúcar sintáctico que permite encadenar las funciones de una manera visualmente lineal (una después de la otra) en lugar de anidar (una dentro de la otra). Por ejemplo:
int totalEven = Enumerable.Sum(Enumerable.Where(myInts, i => i % 2 == 0));
puede escribirse así:
int totalEven = myInts.Where(i => i % 2 == 0).Sum();
Puede 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 indentación o los paréntesis de cierre de Lispy que aparecen al final de la expresión.
Muchas de las otras respuestas afirman que String.Join
es el camino a seguir porque es el más rápido o el más simple de leer. Pero si tomas mi interpretación de '' super-cool LINQ way '', entonces la respuesta es usar String.Join
pero tenerlo envuelto 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 eficiente como la llamada directa (al menos en términos de complejidad del 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á utilizando el estilo de función encadenado .
Dado que esta pregunta tuvo alguna actividad hace un par de semanas, decidí que estaba bien para mí desechar el enfoque combinado Join / Linq que establecí después de ver las respuestas anteriores y los problemas abordados en la respuesta a una pregunta similar (a saber, que Aggregate y Concatenate 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
- funciona para elementos genéricos
- permite usar objetos o propiedades de objetos
- maneja la caja de elementos de 0 largos
- podría usarse con filtros Linq adicionales
- 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
, foreach
), por lo que estaba buscando una solución de Linq-y en primer lugar.
Por supuesto, si alguien ve algún problema con este enfoque, me gustaría adoptar cualquier sugerencia o mejora que puedan tener.
Hay varias respuestas alternativas en esta pregunta anterior , que sin duda estaba apuntando a una matriz de enteros como fuente, pero recibió respuestas generalizadas.