我和同事正在进行一系列编码挑战。
然而,我们喜欢让事情变得更有趣,并将我们的答案打下来(是的,我知道,C#不是最好的高尔夫语言)
我们最近的一个涉及旋转立方体(int [,])。所以最终我们想出了一个赌注,如果我能在一行中得到这个,他会给我买午餐,反之亦然。
经过许多退格和言语之后,我的母亲不愿意听我说,我终于明白了,或者我认为。
我最终得到了int [] []。
据我所知,没有简单的方法将其转换为int [,]。 所以我在一行内询问是否真的有可能。
编辑1
我会发布我的源代码,但后来我的同事可以找到它,我可能会失去免费的午餐。
答案 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");
结果:
如果你坚持幻想:你可以用一个委托动态调用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。