Могу ли я переписать это более элегантно, используя LINQ? - PullRequest
3 голосов
/ 25 февраля 2009

У меня есть double[][], который я хочу преобразовать в формат строки CSV (т.е. каждая строка в строке и элементы строки разделены запятыми). Я написал это так:

public static string ToCSV(double[][] array)
{
    return String.Join(Environment.NewLine,
                       Array.ConvertAll(array,
                                        row => String.Join(",",
                                                           Array.ConvertAll(row, x => x.ToString())));
}

Есть ли более элегантный способ написать это с помощью LINQ?

(Я знаю, можно использовать временные переменные, чтобы улучшить внешний вид, но этот формат кода лучше передает то, что я ищу.)

Ответы [ 4 ]

6 голосов
/ 25 февраля 2009

Можно, но я бы лично не делал все строки одновременно - я бы использовал блок итератора:

public static IEnumerable<string> ToCSV(IEnumerable<double[]> source)
{
    return source.Select(row => string.Join(",",
       Array.ConvertAll(row, x=>x.ToString())));        
}

Это возвращает каждую строку (тогда вызывающая сторона может WriteLine и т. Д. Эффективно, без буферизации всего). Теперь он также может вызываться из любого источника double[] строк (включая, помимо прочего, зубчатый массив).

Также - с локальной переменной вы можете использовать StringBuilder, чтобы сделать каждую строку немного дешевле.


Чтобы вернуть всю строку за раз, я бы оптимизировал ее, чтобы использовать один StringBuilder для всей работы со строками; немного длиннее, но гораздо эффективнее (гораздо меньше промежуточных строк):

public static string ToCSV(IEnumerable<double[]> source) {
    StringBuilder sb = new StringBuilder();
    foreach(var row in source) {
        if (row.Length > 0) {
            sb.Append(row[0]);
            for (int i = 1; i < row.Length; i++) {
                sb.Append(',').Append(row[i]);
            }
        }
    }
    return sb.ToString();
}
2 голосов
/ 26 февраля 2009

Вы также можете использовать Агрегат

public static string ToCSV(double[][] array)
{
  return array.Aggregate(string.Empty, (multiLineStr, arrayDouble) =>
           multiLineStr + System.Environment.NewLine + 
           arrayDouble.Aggregate(string.Empty, (str, dbl) => str + "," + dbl.ToString()));
}
1 голос
/ 26 февраля 2009

Это совместимо с любыми вложенными последовательностями double. Он также откладывает реализацию ToString для вызывающей стороны, позволяя форматировать, избегая беспорядочных IFormatProvider перегрузок:

public static string Join(this IEnumerable<string> source, string separator)
{
    return String.Join(separator, source.ToArray());
}

public static string ToCsv<TRow>(this IEnumerable<TRow> rows, Func<double, string> valueToString)
    where TRow : IEnumerable<double>
{
    return rows
        .Select(row => row.Select(valueToString).Join(", "))
        .Join(Environment.NewLine);
}
1 голос
/ 25 февраля 2009

Вы можете сделать это с LINQ, но я не уверен, нравится ли вам этот лучше, чем ваш Боюсь, что нет. :)

var q = String.Join(Environment.NewLine, (from a in d
                                      select String.Join(", ", (from b in a
                                                                select b.ToString()).ToArray())).ToArray());

Ура, Matthias

...