Can I rewrite this more elegantly using LINQ?

自闭症网瘾萝莉.ら 提交于 2019-12-10 18:18:29

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!