Reputation: 310
A co-worker and I are currently engaged in a series of coding challenges.
However we like to make things slightly more interesting and golf our answers down (Yes I know, C# is not the greatest golfing language)
Our most recent one involved rotating a cube (int[,]). So eventually we came up with a bet, if I can get this in one line he buys me lunch and vice versa.
After many backspaces and words my mother would hate to hear me say, I finally got it, or so I thought.
I ended up with int[][].
And as far as I can see there is no easy way to convert this to int[,]. so I'm asking if it is actually possible within one line.
EDIT 1
I would post my source code, but then my co-worker could find it and I could lose a free lunch.
Upvotes: 4
Views: 233
Reputation: 101122
You'll need at least two lines, one for declaring your result array and one for the actual copying of the data.
You could first flatten your array of array to a single array, and the use Buffer.BlockCopy
to copy all data to the result array.
Here's an example:
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");
Result:
If you insist of being fancy: you could call BlockCopy
dynamically with an delegate to have that delegate return Object
so you can use it for an assignment of an anonymous class, which is apparently in the spirit of your rules, and wrap everything into a collection so you end with a single line monster like this:
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;
Upvotes: 7
Reputation: 111910
You should try learning javascript (the one I'm using is a very common pattern in libraries).
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);
The int[,] array =
can be made a single line just removing the end of lines. I declare an anonymous method and then call it (see the (jagged)
? It is me calling the anonymous method).
single statement version
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);
Here I'm using the Aggregate()
method. The TSeed
is the destination multi-dimensional array. Note the (md[x.i, x.y] = x.val) == x.val ? md : null
: I need to assign the md[x.i, x.y] = x.val
BUT I need to return md
(because Aggregate
requires the function to work this way). I make an useless check(md[x.i, x.y] = x.val) == x.val
and use the ternary operator to return md
.
Note that I'm closing a variable (jagged
), but the closure could be removed (I think).... Mmmmh seems to be complex.
Upvotes: 3
Reputation: 1084
If you are allowed to use Func<>
and lambda you can certainly do it and make a generic extension to transform the object you are calling it on.
/// <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);
}
With this you should be able to transform int[,] to int[][] by doing something like:
int[][] output = input.ForThis<int[][], int[,]>((obj) =>
{
// transform obj == input of type int[,] into int[][]
throw new NotImplementedException();
});
Although I admit that this solution really feels like cheating because you are just sort of wrapping the multiline transformation into a lambda.
Upvotes: 0