Подтвердить что ты не робот

Объединение коллекции объектов в строку с разделителями-запятыми

Во многих местах нашего кода у нас есть коллекции объектов, из которых нам нужно создать список, разделенный запятыми. Тип коллекции различается: это может быть DataTable, из которого нам нужен определенный столбец, или List <Customer> , и т.д.

Теперь мы просматриваем коллекцию и используем конкатенацию строк, например:

string text = "";
string separator = "";
foreach (DataRow row in table.Rows)
{
    text += separator + row["title"];
    separator = ", ";
}

Есть ли лучший образец для этого? В идеале я хотел бы использовать подход, который мы могли бы повторно использовать, просто отправив функцию для получения правильного поля/свойства/столбца от каждого объекта.

4b9b3361

Ответ 1

// using System.Collections;
// using System.Collections.Generic;
// using System.Linq

public delegate string Indexer<T>(T obj);

public static string concatenate<T>(IEnumerable<T> collection, Indexer<T> indexer, char separator)
{
    StringBuilder sb = new StringBuilder();
    foreach (T t in collection) sb.Append(indexer(t)).Append(separator);
    return sb.Remove(sb.Length - 1, 1).ToString();
}

// version for non-generic collections
public static string concatenate<T>(IEnumerable collection, Indexer<T> indexer, char separator)
{
    StringBuilder sb = new StringBuilder();
    foreach (object t in collection) sb.Append(indexer((T)t)).Append(separator);
    return sb.Remove(sb.Length - 1, 1).ToString();
}

// example 1: simple int list
string getAllInts(IEnumerable<int> listOfInts)
{
    return concatenate<int>(listOfInts, Convert.ToString, ',');
}

// example 2: DataTable.Rows
string getTitle(DataRow row) { return row["title"].ToString(); }
string getAllTitles(DataTable table)
{
    return concatenate<DataRow>(table.Rows, getTitle, '\n');
}

// example 3: DataTable.Rows without Indexer function
string getAllTitles(DataTable table)
{
    return concatenate<DataRow>(table.Rows, r => r["title"].ToString(), '\n');
}

Ответ 2

string.Join(", ", Array.ConvertAll(somelist.ToArray(), i => i.ToString()))

Ответ 3

static string ToCsv<T>(IEnumerable<T> things, Func<T, string> toStringMethod)
{
    StringBuilder sb = new StringBuilder();

    foreach (T thing in things)
        sb.Append(toStringMethod(thing)).Append(',');

    return sb.ToString(0, sb.Length - 1); //remove trailing ,
}

Используйте это:

DataTable dt = ...; //datatable with some data
Console.WriteLine(ToCsv(dt.Rows, row => row["ColName"]));

или

List<Customer> customers = ...; //assume Customer has a Name property
Console.WriteLine(ToCsv(customers, c => c.Name));

У меня нет компилятора, но теоретически он должен работать. И, как известно, теоретически практика и теория одинаковы. На практике это не так.

Ответ 4

Я нашел string.Join и Lambda Select > помогает писать минимальный код.

        List<string> fruits = new List<string>();
        fruits.Add("Mango");
        fruits.Add("Banana");
        fruits.Add("Papaya");

        string commaSepFruits = string.Join(",", fruits.Select(f => "'" + f + "'"));
        Console.WriteLine(commaSepFruits);

        List<int> ids = new List<int>();
        ids.Add(1001);
        ids.Add(1002);
        ids.Add(1003);

        string commaSepIds = string.Join(",", ids);
        Console.WriteLine(commaSepIds);

        List<Customer> customers = new List<Customer>();
        customers.Add(new Customer { Id = 10001, Name = "John" });
        customers.Add(new Customer { Id = 10002, Name = "Robert" });
        customers.Add(new Customer { Id = 10002, Name = "Ryan" });

        string commaSepCustIds = string.Join(", ", customers.Select(cust => cust.Id));
        string commaSepCustNames = string.Join(", ", customers.Select(cust => "'" + cust.Name + "'"));

        Console.WriteLine(commaSepCustIds);
        Console.WriteLine(commaSepCustNames);

        Console.ReadLine();

Ответ 5

Вы можете написать функцию, которая преобразует IEnumerable в строку, разделенную запятой

public string Concat(IEnumerable<string> stringList)
{
    StringBuilder textBuilder = new StringBuilder();
    string separator = String.Empty;
    foreach(string item in stringList)
    {
        textBuilder.Append(separator);
        textBuilder.Append(item);
        separator = ", ";
    }
    return textBuilder.ToString();
}

Затем вы можете использовать Linq для запроса вашей коллекции /dataset/etc для предоставления stringList.

Ответ 6

В .NET 4 вы можете просто сделать string.Join(", ", table.Rows.Select(r => r["title"]))

Ответ 7

В стороне: первая модификация, которую я бы сделал, - использовать StringBuilder Class вместо просто String - он будет экономить ресурсы для вас.

Ответ 8

Мне нравится Matt Howells ответить в этом сообщении:

Мне пришлось сделать это в расширение:

public static string ToCsv<T>(this IEnumerable<T> things, Func<T, string> toStringMethod)

Использование: [Я получаю все письма и превращаю их в строку csv для писем]:

var list = Session.Find("from User u where u.IsActive = true").Cast<User>();

return list.ToCsv(i => i.Email);

Ответ 9

string strTest = "1,2,4,6";
string[] Nums = strTest.Split(',');
Console.Write(Nums.Aggregate<string>((first, second) => first + "," + second));
//OUTPUT:
//1,2,4,6

Ответ 10

Вот мой любимый ответ, адаптированный к вопросу, и скорректировано Convert to ConvertAll:

string text = string.Join(", ", Array.ConvertAll(table.Rows.ToArray(), i => i["title"]));