2009-12-17 2 views
2

Скажем, у меня есть список объектов, и объект имеет свойство string. Я хочу получить список разделенных запятыми значений каждого свойства строки для каждого объекта в списке. Вот 1 способ сделать это (без Linq)Другой вопрос Linqification

 

StringBuilder result = new StringBuilder() 
foreach(myObject obj in myList) 
{ 
    result.Append(obj.TheString); 
    result.Append(", "); 
} 
// then trim the trailing ", " and call ToString() on result, etc, etc... 
 

Вот мой первый выстрел в linqification. Есть ли способ лучше?

 

string result = string.Join(", ", myList.Select(myObj => myObj.TheString).ToArray()); 
 

Это одна строка кода, но это не выглядит очень эффективным для меня - перебирать список просто построить массив, только для перебора массива и построить строку ... гмм!

Есть ли лучший способ?

ответ

5

Если вы хотите эффективно, используйте Enumerable.Aggregate с StringBuilder:

string result = myList.Aggregate(new StringBuilder(), 
           (sb, o) => sb.Append(o.TheString).Append(", ")) 
         .ToString(); 

Оригинальная проблема заключается в том, что String.Join хочет массив. В .NET 4 будет перегрузка, которая принимает IEnumerable<string> (и я ожидаю, что она будет реализована, как указано выше).

+0

+1 На самом деле наслаждайтесь ответами, которые показывают, что может сделать Linq! Это завораживает меня, вы можете установить тип результата в StringBuilder (конечно, после удаления .ToString()) и установить точку останова, и найти оценку Linq, которая была сделана до того, как вы конвертируете в строку ... что добавляет к моей путанице -called 'отложенная оценка' в Linq ... но это не ваша проблема! :) Я завернул ваше решение в методе, а затем использовал StringBuilder.Remove, чтобы избавиться от последнего дополнительного пространства и запятой перед преобразованием в строку. Будем экспериментировать с превращением этого в метод расширения. Благодаря ! – BillW

+0

Отложенная оценка отложена для создания 'StringBuilder', но сам' StringBuilder' не откладывается - хотя ничто не мешает писать ленивый 'StringBuilder' (и, теоретически, вполне возможно, что основные строки также ленивы, хотя для чего потребуется поддержка CLR). –

1

Мне нравится этот метод расширения для соединения строк. Это в основном тот же метод, который вы используете, но завернутый в метод расширения. Я бы не рекомендовал его для больших наборов, поскольку эффективность не была целью. Выгода для меня выразительность (очень linqy) и удобно для небольших наборов:

[Test] 
public void Should_make_comma_delimited_list() 
{ 
    var colors = new List<HasColor> 
    { 
     new HasColor { Color = "red" }, 
     new HasColor { Color = "green" }, 
     new HasColor { Color = "blue" } 
    }; 

    var result = colors.Implode(x => x.Color, ", "); 

    Assert.That(result, Is.EqualTo("red, green, blue")); 
} 

public class HasColor 
{ 
    public string Color { get; set; } 
} 

public static class LinqExtensions 
{ 
    public static string Implode<T>(this IEnumerable<T> list, Func<T, string> func, string separator) 
    { 
     return string.Join(separator, list.Select(func).ToArray()); 
    } 
} 
+0

+1 Оцените! – BillW

0

Вот еще один способ (result является StringBuilder):

myList.ForEach(
    myObj => 
    { 
     if (result.Length != 0) 
      result.Append(","); 
     result.Append(myObj.TheString); 
    } 
    ); 
1

Использование string.join, это достаточно хорошо.

Оптимизируйте, когда профайлер скажет вам об этом.

Считывание версии с помощью StringBuilder неудовлетворительно, и вы по-прежнему получаете свою конечную запятую.

Смежные вопросы