Перетворення списку <int> у рядок, розділений комами


116

Чи є спосіб взяти список і перетворити його в рядок, розділений комою?

Я знаю, що я можу просто циклічити і побудувати його, але якось я думаю, що хтось із вас, хлопці, більш крутий спосіб це зробити?

Я дуже хочу вивчити ці типи "хитрощів", ​​тому, будь ласка, поясніть або посилайтесь на документи щодо методу, який ви використовуєте.

Відповіді:


189
List<int> list = ...;
string.Join(",", list.Select(n => n.ToString()).ToArray())

7
Розумна, але повільна і роздута, оскільки вона виділяє по одній струні на елемент. Використання StringBuilder було б набагато ефективнішим.
Стівен Судіт

3
З того, що я бачив в Інтернеті (швидкий пошук) String.Join швидше, ніж використання StringBuilder.
Юрій Факторович


6
Я думаю, що Стівен має на увазі частину n.ToString (), а не String.Join.
Ларсенал

9
Larsenal: але StringBuilder.Append (Int32) внутрішньо викликає ToString по цілому числу. StringBuilder не магічно уникає витрат на виділення рядка для кожного елемента; це просто красиво витягує його з поля зору.
itowlson

115

Просте рішення є

List<int> list = new List<int>() {1,2,3};
string.Join<int>(",", list)

Я використовував це лише зараз у своєму коді, працюючи у функціоналі.


1
Спасибі! це прекрасний підхід
Ірфан Ашраф

2
Це кращий підхід, ніж прийнятий відповідь. При такому підході вам не потрібно імпортувати Linq, і це швидше.
JoKeRxbLaCk

Класно! Я ніколи не знав string.Join має загальні перевантаження. Дякую.
mrmashal


6

Приблизно один газильйонний вирішення трохи складнішої версії цієї проблеми - багато з яких повільні, невмілі або навіть не складаються - дивіться коментарі до моєї статті з цього приводу:

http://blogs.msdn.com/ericlippert/archive/2009/04/15/comma-quibbling.aspx

та коментар StackOverflow:

Виклик Еріка Ліпперта "переслідування комами", найкраща відповідь?


Дякуємо за посилання. Ця проблема зв'язування рядків виявилася більш складною та більш навчальною, ніж я очікував!
Стівен Судіт

4

Для додаткової прохолоди я зробив би цей метод розширення на IEnumerable <T>, щоб він працював на будь-якому IEnumerable:

public static class IEnumerableExtensions {
  public static string BuildString<T>(this IEnumerable<T> self, string delim = ",") {
    return string.Join(delim, self)        
  }
}

Використовуйте його наступним чином:

List<int> list = new List<int> { 1, 2, 3 };
Console.WriteLine(list.BuildString(", "));

Дві можливі оптимізації: 1) Додайте деліметр після кожного елемента незалежно, а потім видаліть додатковий після закінчення циклу. 2) Вкажіть ємність для StringBuilder.
Стівен Судіт

1
Якщо ви викопаєте Reflector, виявиться, що Join підсумовує довжини, щоб попередньо розрахувати розмір буфера, а також "прогрунтує насос", додавши перший рядок поза петлею, а потім, всередині циклу, беззастережно додавши роздільник перед наступний рядок У поєднанні з деякими небезпечними / внутрішніми хитрощами це повинно бути дуже швидким.
Стівен Судіт

@Steven: дотримуйтесь ваших порад.
cdiggins

1
Ви жорстко вкажіть роздільник у своєму розширенні та ігноруєте пропущене значення для роздільника та пропустили крапку з комою. Це має бутиreturn string.Join(delim, self);
Андрій

1

Здається, досить швидко.

IList<int> listItem = Enumerable.Range(0, 100000).ToList();
var result = listItem.Aggregate<int, StringBuilder, string>(new StringBuilder(), (strBuild, intVal) => { strBuild.Append(intVal); strBuild.Append(","); return strBuild; }, (strBuild) => strBuild.ToString(0, strBuild.Length - 1));

1

Мій "розумний" запис:

        List<int> list = new List<int> { 1, 2, 3 };
        StringBuilder sb = new StringBuilder();
        var y = list.Skip(1).Aggregate(sb.Append(x.ToString()),
                    (sb1, x) =>  sb1.AppendFormat(",{0}",x));

        // A lot of mess to remove initial comma
        Console.WriteLine(y.ToString().Substring(1,y.Length - 1));

Просто не зрозумів, як умовно додати кому.


1
Будь ласка, не пишіть Selectз побічними ефектами в лямбда. У цьому випадку ви навіть цього не використовуєте y, тому ваш Selectпо суті є просто foreach- тому запишіть його як таке.
Павло Мінаєв

Я не пропонував це як гарне рішення. ОП хотіла чогось цікавішого, ніж передбачити
Larsenal

Так, але зловживання, Selectколи foreachпроходить повз "цікаве" і, ну, "зловживання". Більш цікавий підхід тут повинен був би використовувати Enumerable.Aggregateз StringBuilderяк початкове значення - спробувати.
Павло Мінаєв

Гарна ідея. Я мушу вийти, але я можу надати цей вир.
Ларсенал

0

ви можете використовувати бібліотеку System.Linq; Це більш ефективно:

using System.Linq;
string str =string.Join(",", MyList.Select(x => x.NombreAtributo));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.