# Array reshaping without explicitly specifying one dimension

In NumPy a function numpy.reshape can leave at most one dimensional specification unspecified and it will be automatically calculated.

So is there a similar functionality in MMA? As a simplest example I can think of, when I would like to evenly split a List with an even-number length, can I not explicitly calculate the length of the two sublists?

list = Range[6];
ArrayReshape[#, {2, Length[#]/2}] & [list] (*working*)
Partition[#, Length[#]/2] & [list] (*working*)
ArrayReshape[list, {2, _}] (*not working*)


The last line is my naïve attempt and apparently it does not work.

• It's a strange oversight, but I don't think ArrayReshape offers this sort of functionality. I'd expect that you could use Automatic for one of the dimensions, but that doesn't work. Aug 13, 2020 at 12:31
• @SjoerdSmit It does not have to be ArrayReshape, anything as long as an MMA function is OK. Aug 13, 2020 at 12:33
• Via a circuitous route: Multicolumn[list, 2] // Normal // Transpose Aug 13, 2020 at 12:38
• A good candidate for the Function Repository...
– flip
Aug 13, 2020 at 15:14
• Actually, you narrowed question to the 2d case, but numpy.reshape with argument -1 works for arbitrary dimensions. It would be interesting to reproduce exactly this with mathematica. Aug 13, 2020 at 19:37

ArrayReshape doesn't let you do this, but ReshapeLayer does:

ReshapeLayer[{2, Automatic}] @ Range[6]
ReshapeLayer[{Automatic, 2}] @ Range[6]


{{1., 2., 3.}, {4., 5., 6.}}

{{1., 2.}, {3., 4.}, {5., 6.}}

Unfortunately, ReshapeLayer is a neural network function that only works on machine numbers.

• Interesting! But there is a little flaw as you have pointed out. Aug 13, 2020 at 12:37
• It also fails on some machine inputs: ReshapeLayer[{Automatic, 2}]@ N[{1, 1, 1, 1.*^39}] Aug 14, 2020 at 3:13

It's easy enough to compute the missing dimension, which the OP shows, although it would be nice if Automatic worked in the way below.

list = Range[24];
dims = {2, Automatic, 4};
ArrayReshape[
list,
dims /. Automatic ->  (* drops elements that don't fit new dims which *)
Quotient[Times @@ Dimensions[list],  (* is what ArrayReshape[] does *)
Times @@ DeleteCases[dims, Automatic]]]

(*
{{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}},
{{13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24}}}
*)


General function:

ClearAll[arrayReshape];
arrayReshape[
a_?ArrayQ,
dims : {(_Integer | Automatic) ..} /; Count[dims, Automatic] <= 1,
p_ : None] :=
ArrayReshape[
a,
dims /. Automatic ->
Quotient[Times @@ Dimensions[a],
Times @@ DeleteCases[dims, Automatic]],
p]


Example:

ReshapeLayer[{Automatic, 20}]@Range[600] //  Dimensions // RepeatedTiming
arrayReshape[Range[600], {Automatic, 20}] // Dimensions // RepeatedTiming

(*
{0.0059, {30, 20}}
{0.0000119, {30, 20}}
*)


One ought to beware that ReshapeLayer has considerable overhead and limitations compared to ArrayReshape.

• ReshapeLayer does indeed have overhead, but the converse is also true. Neural network functions are very fast for large amounts of data and can be very efficiently parallelized on your GPU. If you have lots of large arrays to reshape, I'm pretty sure ReshapeLayer will beat ArrayReshape. Aug 14, 2020 at 7:09
• @SjoerdSmit That's an interesting assertion. I cannot verify it on my MacBook Pro, but it's probably hardware dependent. On Range[600000000] (4.5GB), ReshapeLayer uses 9GB (and 20 sec.), but ArrayReshape uses only 4.5GB (and 1.7 sec.). Copying the array takes almost 4 sec., so if the ArrayReshape call necessitates copying the array, it takes longer, 5-6 sec. But I suspect ArrayReshape works in a way such that no advantage from parallelization can be had. Aug 14, 2020 at 12:00
• All neural network layers can handle multiple inputs. They automatically map over lists of arguments in the same way as Compile[... RuntimeAttributes -> {Listable}]. If you have many arrays you need to reshape, this should give ReshapeLayer an advantage over mapping ArrayReshape, I think. Aug 14, 2020 at 12:04
• @SjoerdSmit I guess I don't understand. This fails: ReshapeLayer[{Automatic, 2}]@{Range@6, Range@8} Aug 14, 2020 at 12:09
• Hmmm, maybe you're right about that. I'm not quite sure at what stage ReshapeLayer infers its input and output dimensions. Aug 14, 2020 at 12:17