Могу ли я переписать это более элегантно, используя LINQ?
У меня есть 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?
(Я знаю, можно использовать временные переменные, чтобы сделать это лучше, но этот формат кода лучше передает то, что я ищу.)
Ответы
Ответ 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);
}
Ответ 2
Вы можете, но я лично не буду делать все строки сразу - я бы использовал блок итератора:
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();
}
Ответ 3
Вы также можете использовать Aggregate
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()));
}
Ответ 4
Вы можете сделать это с помощью 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