在C#中将2D数组转换为字符串,寻找最优雅的方式

时间:2017-10-08 11:25:36

标签: c# arrays linq multidimensional-array tostring

我无法相信没有聪明的方法可以从二维阵列中获得这样的东西 在这种情况下int[,] a

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

我已经阅读了许多类似的问题,并了解到string.Join()只能用于锯齿状阵列(2D)。但是我不想使用它们,因为更复杂的初始化,并且当我的行(全部具有相同长度)分布在内存中的几个位置时感觉很糟糕。

这是我的#34;正常"代码:

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 += '}';
}

这里有一个高尔夫&#34;之一:

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

:) - 也不是很优雅,可读性也不错。

有什么建议吗?我对Linq开放,因为它不必快速。我对改进代码的优雅感兴趣,但不仅仅是将它转移到扩展方法。

4 个答案:

答案 0 :(得分:3)

AFAIK,当我们想要一个来自对象的字符串时,我们正在调用序列化,所以我更喜欢使用像 Newtonsoft.Json 这样的序列化器:

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

使用简单for之类的解决方案并删除if的方式可以是 - 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);

建议使用StringBuilder来提高大数组的性能:

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();

答案 1 :(得分:2)

Linq解决方案,而不是性能明智。

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))}}}"));

请注意,您在2d数组上不能Select,但是您可以使用OfType来返回2d数组的可枚举数,枚举数将横向遍历2d数组。

x.index / a.GetLength(1)只是将每个索引划分为总行数。所以,如果你有3行,你的索引将相当于3行分发。

最后,对每个组进行字符串连接。

更简化的版本。 (格式化分组的结果选择器)

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 :(得分:1)

考虑这种方法:

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();

它与你的非常相似,但使用的是LINQ。 它将二维数组投影到可枚举的LINQ中,然后用大括号包装它并在需要的地方添加逗号。

答案 3 :(得分:0)

仅当您不介意以连续方式显示数据以及边界是静态且始终已知时,才发布此答案仅供参考。

您可以只使用LINQ Cast,然后使用string.Join将字符串输出为纯csv。

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

要解析回它:

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]);

请参见示例here

相关问题