2009-02-25 4 views
3

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

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

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

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

+0

Re: «Я на самом деле пытаюсь научиться LINQ»; LINQ - это просто инструмент; возможно, один из самых важных уроков для обучения LINQ - это когда не использовать его? –

+0

Может быть. Я бы не использовал LINQ для этого метода в реальном приложении, но его легче узнать, когда у него есть реальное требование думать (а не некоторые надуманные примеры). –

+0

Повторите свой пост измерений: тогда я подозреваю, что ваши измерения подозрительны ... ухаживать за публикацией? –

ответ

1

Это совместимо с любыми вложенными последовательностями 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); 
} 
6

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

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(); 
} 
+0

Спасибо. Но только ради изучения, как бы вы превратили его в одну строку? 'String.Join (Environment.NewLine, ToCSV (источник) .ToArray())' например? –

+0

Я бы хотел использовать один StringBuilder - см. Обновление –

+0

Спасибо. Я это понимаю, но эффективность здесь не в этом. Я на самом деле пытаюсь узнать LINQ. :) –

1

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

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

Cheers, Matthias

2

Вы также можете использовать Совокупные

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())); 
} 
Смежные вопросы