Convert 2D array to string in C#, looking for most elegant way

淺唱寂寞╮ 提交于 2019-12-11 02:16:45

问题


I cannot believe there is no smart way to get something like this from a 2D array,
in this case int[,] a:

"{1,2,3},{4,5,6},{7,8,9}"

I have read many similar questions and learned that string.Join() can only be used on jagged arrays (in 2D). But I don't want to use them because of the more complex initialization and because it just feels bad when my rows, which all have the same length, are spread over several places in memory.

This is my "normal" code:

var s = "";
for (int i = 0; i < a.GetLength(0); i++) {
    if (i > 0) s += ',';
    s += '{';
    for (int j = 0; j < a.GetLength(1); j++) {
        if (j > 0) s += ',';
        s += a[i, j];
    }
    s += '}';
}

And here a "golfed" one:

var s = "{";
var i = 0;
foreach (var item in a) s += (i++ > 0 ? i % a.GetLength(1) == 1 ? "},{" : "," : "") + item;
s += '}';

:) - not really elegant, too, and the readability is more than bad.

Any suggestions? I'm open to Linq, since it doesn't have to be fast. I'm interested in improving elegance of the code, but not by just moving it to an extension method.


回答1:


Linq solution, not performance wise.

var str = string.Join(",", a.OfType<int>()
    .Select((value, index) => new {value, index})
    .GroupBy(x => x.index / a.GetLength(1))
    .Select(x => $"{{{string.Join(",", x.Select(y => y.value))}}}"));

Note that you cant Select on 2d array, but you can use OfType which will return an enumerable for 2d array, the enumerator will traverse through 2d array horizontally.

x.index / a.GetLength(1) simply divides each index to total number of rows. so if you have 3 rows, your indexes will be distributed through 3 rows equivalently.

lastly string join is operated on each group.


A little more simplified version. (format inside result selector of grouping)

var str = string.Join(",", a.OfType<int>()
    .Select((value, index) => new {value, index})
    .GroupBy(x => x.index / a.GetLength(1), x => x.value,
        (i, ints) => $"{{{string.Join(",", ints)}}}"));



回答2:


AFAIK, when we want a string from an object, we are calling about serializing, So I prefer to use a serializer like Newtonsoft.Json:

var result = $@"{{{JsonConvert.SerializeObject(a)
    .Trim('[', ']').Replace("[", "{").Replace("]", "}")}}}";

A way by using simple fors like your solution and with removing ifs can be - this code will be faster for small arrays -:

var result = string.Empty;
var maxI = a.GetLength(0);
var maxJ = a.GetLength(1);
for (var i = 0; i < maxI; i++)
{
    result += ",{";
    for (var j = 0; j < maxJ; j++)
    {
        result += $"{a[i, j]},";
    }

    result += "}";
}

result = .Replace(",}", "}").Substring(1);

As suggested to use StringBuilder to improve performance just for big arrays:

var sb = new StringBuilder(string.Empty);
var maxI = a.GetLength(0);
var maxJ = a.GetLength(1);
for (var i = 0; i < maxI; i++)
{
    sb.Append(",{");
    for (var j = 0; j < maxJ; j++)
    {
        sb.Append($"{a[i, j]},");
    }

    sb.Append("}");
}

sb.Replace(",}", "}").Remove(0, 1);
var result = sb.ToString();



回答3:


Consider this approach:

var numbers = new int[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };

var results = string.Join(",",
    Enumerable.Range(0, numbers.GetUpperBound(0) + 1)
        .Select(x => Enumerable.Range(0, numbers.GetUpperBound(1) + 1)
            .Select(y => numbers[x, y]))
        .Select(z => "{" + string.Join(",", z) + "}"));

Console.WriteLine(results);

Console.ReadLine();

It is quite similar to yours, but using LINQ instead. It projects the two dimensional array into a LINQ enumerable, and then wraps it with braces and adds commas where needed.




回答4:


Posting this answer just for the reference, for when you don't mind the data to be presented in a continuous manner and when the bounds are static and always known.

You can just output your string as plain csv, using LINQ Cast, then string.Join.

var array = new int[2,3] { { 1, 2, 3 }, { 1, 2, 3 } };
var output = string.Join(',', array.Cast<int>());

To parse it back:

var input = new int[upperLen,lowerLen];
for (var upper = 0; upper < upperLen; upper++)
    for(var lower = 0; lower < lowerLen; lower++)
        input[upper, lower] = int.Parse(parsed[(upper * lowerLen) + lower]);

See example here.



来源:https://stackoverflow.com/questions/46630565/convert-2d-array-to-string-in-c-looking-for-most-elegant-way

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