锯齿状到多维数组

时间:2018-05-25 06:23:23

标签: c# linq

我和同事正在进行一系列编码挑战。

然而,我们喜欢让事情变得更有趣,并将我们的答案打下来(是的,我知道,C#不是最好的高尔夫语言)

我们最近的一个涉及旋转立方体(int [,])。所以最终我们想出了一个赌注,如果我能在一行中得到这个,他会给我买午餐,反之亦然。

经过许多退格和言语之后,我的母亲不愿意听我说,我终于明白了,或者我认为。

我最终得到了int [] []。

据我所知,没有简单的方法将其转换为int [,]。 所以我在一行内询问是否真的有可能。

  

编辑1

我会发布我的源代码,但后来我的同事可以找到它,我可能会失去免费的午餐。

3 个答案:

答案 0 :(得分:7)

您至少需要两行,一行用于声明结果数组,另一行用于实际复制数据。

您可以先将数组数组展平为单个数组,然后使用Buffer.BlockCopy将所有数据复制到结果数组中。

以下是一个例子:

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

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

var result = new int[4, 4];
// count = source.Length * source[0].Length * sizeof(int) = 64, since BlockCopy is byte based
// to be dynamically you could also use System.Runtime.InteropServices.Marshal.SizeOf(source[0][0]) instead of sizeof(int)
Buffer.BlockCopy(source.SelectMany(r => r).ToArray(), 0, result, 0, 64);

result.Dump("result");
expected.Dump("expected");

结果:

enter image description here

如果你坚持幻想:你可以用一个委托动态调用BlockCopy让该委托返回Object,这样你就可以用它来分配一个匿名类,这显然是在你的规则的精神,并将所有内容包装成一个集合,所以你最终得到一个像这样的单行怪物:

var result = new[]{ new int[4, 4] }.Select(x => new { r = x, tmp = Delegate.CreateDelegate(typeof(Action<Array, int, Array, int, int>), typeof(Buffer).GetMethod("BlockCopy")).DynamicInvoke(new Object[]{source.SelectMany(r => r).ToArray(), 0, x, 0, 64})}).First().r;

答案 1 :(得分:3)

你应该尝试学习javascript(我正在使用的是一个非常常见的库模式)。

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

int[,] array = ((Func<int[][], int[,]>)(x =>
{
    int[,] temp = new int[x.Length, x.Length != 0 ? x[0].Length : 0];
    for (int i = 0; i < x.Length; i++)
    {
        for (int j = 0; j < x[0].Length; j++)
        {
            temp[i, j] = x[i][j];
        }
    }

    return temp;
}))(jagged);

可以将int[,] array =组成一行,只删除行尾。我声明了一个匿名方法,然后调用它(参见(jagged)?这是我调用匿名方法。)

单一声明版本

int[,] array = jagged.Length == 0 ? 
    new int[0,0] : 
    jagged.SelectMany(x => x)
        .Select((x, ix) => new
        {
            i = ix / jagged[0].Length,
            y = ix % jagged[0].Length,
            val = x
        })
        .Aggregate(new int[jagged.Length, jagged[0].Length], (md, x) => (md[x.i, x.y] = x.val) == x.val ? md : null);

我在这里使用Aggregate()方法。 TSeed是目标多维数组。注意(md[x.i, x.y] = x.val) == x.val ? md : null:我需要分配md[x.i, x.y] = x.val但我需要返回md(因为Aggregate要求函数以这种方式工作)。我做了一个无用的检查(md[x.i, x.y] = x.val) == x.val并使用三元运算符返回md

请注意,我正在关闭一个变量(jagged),但是可以删除闭包(我认为)......嗯嗯似乎很复杂。

答案 2 :(得分:0)

如果您被允许使用Func<>和lambda,您当然可以执行此操作并创建一个通用扩展来转换您调用它的对象。

/// <typeparam name="T">Output type</typeparam>
/// <typeparam name="U">Calling type</typeparam>
/// <param name="obj">object to pipe</param>
/// <param name="func">blackbox function</param>
/// <returns>whatever</returns>
public static T ForThis<T,U> (this U obj, Func<U,T> func)
{
    return func(obj);
}

通过这样做,您应该能够通过执行以下操作将int [,]转换为int [] []:

int[][] output = input.ForThis<int[][], int[,]>((obj) =>
{
    // transform obj == input of type int[,] into int[][]
    throw new NotImplementedException();
});

虽然我承认这个解决方案真的像是作弊,因为你只是将多线转换包装成一个lambda。