问题
I have a double[][]
that I want to convert to a CSV string format (i.e. each row in a line, and row elements separated by commas). I wrote it like this:
public static string ToCSV(double[][] array)
{
return String.Join(Environment.NewLine,
Array.ConvertAll(array,
row => String.Join(",",
Array.ConvertAll(row, x => x.ToString())));
}
Is there a more elegant way to write this using LINQ?
(I know, one could use temporary variables to make this look better, but this code format better conveys what I am looking for.)
回答1:
This is compatible with any nested sequences of double
. It also defers the ToString
implementation to the caller, allowing formatting while avoiding messy IFormatProvider
overloads:
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:
You can, but I wouldn't personally do all the lines at once - I'd use an iterator block:
public static IEnumerable<string> ToCSV(IEnumerable<double[]> source)
{
return source.Select(row => string.Join(",",
Array.ConvertAll(row, x=>x.ToString())));
}
This returns each line (the caller can then WriteLine
etc efficiently, without buffering everything). It is also now callable from any source of double[]
rows (including but not limited to a jagged array).
Also - with a local variable you could use StringBuilder
to make each line slightly cheaper.
To return the entire string at once, I'd optimize it to use a single StringBuilder
for all the string work; a bit more long-winded, but much more efficient (far fewer intermediate strings):
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:
You could also use 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:
You can do it with LINQ, but I'm not sure if you like this one better than yours. I'm afraid you don't. :)
var q = String.Join(Environment.NewLine, (from a in d
select String.Join(", ", (from b in a
select b.ToString()).ToArray())).ToArray());
Cheers, Matthias
来源:https://stackoverflow.com/questions/585215/can-i-rewrite-this-more-elegantly-using-linq