Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to unflatten an array ?

91 views
Skip to first unread message

Valeri Astanoff

unread,
Sep 30, 2010, 4:53:29 AM9/30/10
to
Good day,

Suppose I have a flat array like this :

{{1, 0, 1}, {1, 1, 1}, {1, 2, 3}, {2, 0, 5}...

and I want to get back to this "unflattened" form :

{{{{1, 0}, 1}, {{1, 1}, 1}, {{1, 2}, 3}}, {{{2, 0}, 5}...

What is the most efficient way to do it ?


All I have found is this :

In[1]:= unflatten[arr : {{_, _, _} ..}] :=
Module[{f},
Scan[(f[#[[1]], #[[2]]] = #[[3]]) &, arr];
Table[{{x, y}, f[x, y]},
{x, arr[[All, 1]] // Union},
{y, arr[[All, 2]] // Union}]
];

In[2]:= a1 = {{{{1, 0}, 1}, {{1, 1}, 1}, {{1, 2}, 3}},
{{{2, 0}, 5}, {{2, 1}, 0}, {{2, 2}, 0}}, {{{3, 0}, 4},
{{3, 1}, 5}, {{3, 2}, 2}}, {{{5, 0}, 1}, {{5, 1}, 3},
{{5, 2}, 2}}};

In[3]:= a2 = Flatten /@ Flatten[a1, 1]

Out[3]= {{1, 0, 1}, {1, 1, 1}, {1, 2, 3}, {2, 0, 5},
{2, 1, 0}, {2, 2, 0}, {3, 0, 4}, {3, 1, 5}, {3, 2, 2},
{5, 0, 1}, {5, 1, 3}, {5, 2, 2}}

In[4]:= a3 = unflatten@a2

Out[4]= {{{{1, 0}, 1}, {{1, 1}, 1}, {{1, 2}, 3}},
{{{2, 0}, 5}, {{2, 1}, 0}, {{2, 2}, 0}}, {{{3, 0}, 4},
{{3, 1}, 5}, {{3, 2}, 2}}, {{{5, 0}, 1}, {{5, 1}, 3},
{{5, 2}, 2}}}

In[5]:= a1 == a3

Out[5]= True


Please help me to something faster for large arrays.

--
Valeri Astanoff

Raffy

unread,
Oct 1, 2010, 5:41:10 AM10/1/10
to

m = {{1, 0, 1}, {1, 1, 1}, {1, 2, 3}, {2, 0, 5}...

Transpose@{m[[All, ;; -2]], m[[All, -1]]}

Bob Hanlon

unread,
Oct 1, 2010, 5:42:37 AM10/1/10
to

unflatten[arr : {{_, _, _} ..}] :=
SplitBy[{Most[#], Last[#]} & /@ arr, #[[1, 1]] &]

a1 = {{{{1, 0}, 1}, {{1, 1}, 1}, {{1, 2}, 3}}, {{{2, 0}, 5}, {{2, 1},
0}, {{2, 2}, 0}}, {{{3, 0}, 4}, {{3, 1}, 5}, {{3, 2},
2}}, {{{5, 0}, 1}, {{5, 1}, 3}, {{5, 2}, 2}}};

a2 = Flatten /@ Flatten[a1, 1];

a1 == unflatten@a2

True


Bob Hanlon

---- Valeri Astanoff <asta...@gmail.com> wrote:

=============

Mark Adler

unread,
Oct 1, 2010, 5:42:47 AM10/1/10
to
Don't know if it's the most efficient, but I would do this:

Partition[{{#1, #2}, #3} & @@@ a2, 3] === a1
True

Mark

Leonid Shifrin

unread,
Oct 1, 2010, 5:42:58 AM10/1/10
to
Hi Valeri,

It is not clear to me how your sublists are partitioned within the big list
in the unflattened version - always by 3 together, or some other principle?

Your function seems to work by pure accident. Consider random data of your
form instead of your a1:

In[50]:==
rnda ==
Partition[Table[{{RandomInteger[{0,10}],RandomInteger[{0,10}]},RandomIntege=
r[{0,10}]},{9}],3]

Out[50]==
{{{{8,8},7},{{2,1},7},{{3,1},7}},{{{10,9},1},{{8,9},10},{{10,5},8}},{{{9,10=
},6},{{9,8},1},{{7,6},1}}}

In[51]:== rnda2 == Flatten/@Flatten[rnda,1]

Out[51]==
{{8,8,7},{2,1,7},{3,1,7},{10,9,1},{8,9,10},{10,5,8},{9,10,6},{9,8,1},{7,6,1=
}}

In[52]:== unflatten@rnda2

Out[52]==
{{{{2,1},7},{{2,5},f$2163[2,5]},{{2,6},f$2163[2,6]},{{2,8},f$2163[2,8]},{{2=
,9},f$2163[2,9]},{{2,10},f$2163[2,10]}},{{{3,1},7},{{3,5},f$2163[3,5]},{{3,=
6},f$2163[3,6]},{{3,8},f$2163[3,8]},{{3,9},f$2163[3,9]},{{3,10},f$2163[3,10=
]}},{{{7,1},f$2163[7,1]},{{7,5},f$2163[7,5]},{{7,6},1},{{7,8},f$2163[7,8]},=
{{7,9},f$2163[7,9]},{{7,10},f$2163[7,10]}},{{{8,1},f$2163[8,1]},{{8,5},f$21=
63[8,5]},{{8,6},f$2163[8,6]},{{8,8},7},{{8,9},10},{{8,10},f$2163[8,10]}},{{=
{9,1},f$2163[9,1]},{{9,5},f$2163[9,5]},{{9,6},f$2163[9,6]},{{9,8},1},{{9,9}=
,f$2163[9,9]},{{9,10},6}},{{{10,1},f$2163[10,1]},{{10,5},8},{{10,6},f$2163[=
10,6]},{{10,8},f$2163[10,8]},{{10,9},1},{{10,10},f$2163[10,10]}}}

So, it gives a mess here. Either it uses some data format-specific
information in some non-obvious way (but then you had to give us a more
precise format specification for you unflattened list), - and then my
randomly generated data simply do not comply with your format, or your
function is wrong.

Assuming constant partitioning by 3 sublists in the main unflattened list,
here is my attempt:

In[61]:==
a1 == {{{{1, 0}, 1}, {{1, 1}, 1}, {{1, 2}, 3}}, {{{2, 0},


5}, {{2, 1}, 0}, {{2, 2}, 0}}, {{{3, 0}, 4}, {{3, 1},
5}, {{3, 2}, 2}}, {{{5, 0}, 1}, {{5, 1}, 3}, {{5, 2}, 2}}};

In[62]:==
a3 == Partition[Transpose[{a1fl[[All, {1, 2}]], a1fl[[All, 3]]}], 3]

Out[62]== {{{{1, 0}, 1}, {{1, 1}, 1}, {{1, 2}, 3}}, {{{2, 0},


5}, {{2, 1}, 0}, {{2, 2}, 0}}, {{{3, 0}, 4}, {{3, 1}, 5}, {{3, 2},
2}}, {{{5, 0}, 1}, {{5, 1}, 3}, {{5, 2}, 2}}}

In[63]:== a3 ====== a1

Out[63]== True

Regards,
Leonid


On Thu, Sep 30, 2010 at 12:52 PM, Valeri Astanoff <asta...@gmail.com>wrote=
:

> Good day,
>
> Suppose I have a flat array like this :
>
> {{1, 0, 1}, {1, 1, 1}, {1, 2, 3}, {2, 0, 5}...
>
> and I want to get back to this "unflattened" form :
>
> {{{{1, 0}, 1}, {{1, 1}, 1}, {{1, 2}, 3}}, {{{2, 0}, 5}...
>
> What is the most efficient way to do it ?
>
>
> All I have found is this :
>

> In[1]:== unflatten[arr : {{_, _, _} ..}] :==
> Module[{f},
> Scan[(f[#[[1]], #[[2]]] == #[[3]]) &, arr];


> Table[{{x, y}, f[x, y]},
> {x, arr[[All, 1]] // Union},
> {y, arr[[All, 2]] // Union}]
> ];
>

> In[2]:== a1 == {{{{1, 0}, 1}, {{1, 1}, 1}, {{1, 2}, 3}},


> {{{2, 0}, 5}, {{2, 1}, 0}, {{2, 2}, 0}}, {{{3, 0}, 4},
> {{3, 1}, 5}, {{3, 2}, 2}}, {{{5, 0}, 1}, {{5, 1}, 3},
> {{5, 2}, 2}}};
>

> In[3]:== a2 == Flatten /@ Flatten[a1, 1]
>
> Out[3]== {{1, 0, 1}, {1, 1, 1}, {1, 2, 3}, {2, 0, 5},


> {2, 1, 0}, {2, 2, 0}, {3, 0, 4}, {3, 1, 5}, {3, 2, 2},
> {5, 0, 1}, {5, 1, 3}, {5, 2, 2}}
>

> In[4]:== a3 == unflatten@a2
>
> Out[4]== {{{{1, 0}, 1}, {{1, 1}, 1}, {{1, 2}, 3}},


> {{{2, 0}, 5}, {{2, 1}, 0}, {{2, 2}, 0}}, {{{3, 0}, 4},
> {{3, 1}, 5}, {{3, 2}, 2}}, {{{5, 0}, 1}, {{5, 1}, 3},
> {{5, 2}, 2}}}
>

> In[5]:== a1 ==== a3
>
> Out[5]== True

Ray Koopman

unread,
Oct 1, 2010, 5:43:09 AM10/1/10
to
On Sep 30, 1:53 am, Valeri Astanoff <astan...@gmail.com> wrote:

Partition[{Most@#,Last@#}&/@a2, 3]

Chris Degnen

unread,
Oct 1, 2010, 5:43:20 AM10/1/10
to

(* Your function *)


unflatten[arr : {{_, _, _} ..}] :=
Module[{f}, Scan[(f[#[[1]], #[[2]]] = #[[3]]) &, arr];
Table[{{x, y}, f[x, y]}, {x, arr[[All, 1]] // Union}, {y,
arr[[All, 2]] // Union}]];

a1 = {{{{1, 0}, 1}, {{1, 1}, 1}, {{1, 2}, 3}}, {{{2, 0}, 5}, {{2, 1},
0}, {{2, 2}, 0}}, {{{3, 0}, 4}, {{3, 1}, 5}, {{3, 2},
2}}, {{{5, 0}, 1}, {{5, 1}, 3}, {{5, 2}, 2}}};

a2 = Flatten /@ Flatten[a1, 1]

a3 = unflatten@a2
a1 == a3
(* Alternative method *)
a3 = {{#1, #2}, #3} & @@@ # & /@ Partition[a2, 3]
a1 == a3
(* Timing tests *)
a2Large = Flatten[ConstantArray[a2, 1000], 1];
a2LargeTime = Part[Timing[unflatten@a2Large], 1]
a2LargeTime =
Part[Timing[{{#1, #2}, #3} & @@@ # & /@ Partition[a2Large, 3]], 1]

Sseziwa Mukasa

unread,
Oct 1, 2010, 5:43:52 AM10/1/10
to

I would construct the desired result as:

Partition[{Most[#],Last[#]}&/@a2,3]

Comparing on a array of 10002 triples the timing of the two algorithms is

(Debug) In[244]:= a4 = RandomInteger[{-10, 10}, {100002, 3}];
First[Timing[unflatten[a4];]]
First[Timing[Partition[{Most[#], Last[#]} & /@ a4, 3];]]
(Debug) Out[245]= 1.39615
(Debug) Out[246]= 0.549411

Regards,
Sseziwa

Valeri Astanoff

unread,
Oct 2, 2010, 5:45:28 AM10/2/10
to
On 1 oct, 11:42, Bob Hanlon <hanl...@cox.net> wrote:
> unflatten[arr : {{_, _, _} ..}] :=
> SplitBy[{Most[#], Last[#]} & /@ arr, #[[1, 1]] &]
>
> a1 = {{{{1, 0}, 1}, {{1, 1}, 1}, {{1, 2}, 3}}, {{{2, 0}, 5}, {{2, 1},
> 0}, {{2, 2}, 0}}, {{{3, 0}, 4}, {{3, 1}, 5}, {{3, 2},
> 2}}, {{{5, 0}, 1}, {{5, 1}, 3}, {{5, 2}, 2}}};
>
> a2 = Flatten /@ Flatten[a1, 1];
>
> a1 == unflatten@a2
>
> True
>
> Bob Hanlon
>

Good day,

I have to apologize for not being very clear about what I wanted.
Seems that you, Bob, were the only one to understand what I meant.
[I had to replace SplitBy with Split cause I only have version 6]
Any way I have to thank everyone who tried and help me.
Maybe this test will more explicit than my poor previous example :

In[1]:= a1 =
Table[{{x, y}, RandomInteger[{0, 99}]}, {x, 0, 99}, {y, 0, 49}] ;

In[2]:= Dimensions[a1]
Out[2]= {100, 50, 2}

In[3]:= a2 = Flatten /@ Flatten[a1, 1] ;

In[4]:= Dimensions[a2]
Out[4]= {5000, 3}

In[5]:= unflatten[arr : {{_, _, _} ..}] :=


Module[{f}, Scan[(f[#[[1]], #[[2]]] = #[[3]]) &, arr];
Table[{{x, y}, f[x, y]}, {x, arr[[All, 1]] // Union}, {y,
arr[[All, 2]] // Union}]];

In[6]:= (a3 = unflatten[a2];) // Timing
Out[6]= {0.532, Null}

In[7]:= Dimensions[a3]
Out[7]= {100, 50, 2}

In[8]:= a1 == a3
Out[8]= True

In[9]:= unflattenRaffy[arr_] :=
Transpose@{arr[[All, ;; -2]], arr[[All, -1]]}

In[10]:= (a3 = unflattenRaffy[a2] ; ) // Timing
Out[10]= {0.016, Null}

In[11]:= Dimensions[a3]
Out[11]= {5000, 2}

In[12]:= a1 == a3
Out[12]= False

In[13]:= unflattenBob[arr : {{_, _, _} ..}] :=
Split[{Most[#], Last[#]} & /@ arr, #1[[1, 1]] == #2[[1, 1]] &]

In[14]:= (a3 = unflattenBob[a2] ;) // Timing
Out[14]= {0.062, Null}

In[15]:= Dimensions[a3]
Out[15]= {100, 50, 2}

In[16]:= a1 == a3
Out[16]= True

In[17]:= unflattenMark[arr_] :=
Partition[{{#1, #2}, #3} & @@@ arr, 3]

In[18]:= (a3 = unflattenMark[a2] ;) // Timing
Out[18]= {0.032, Null}

In[19]:= Dimensions[a3]
Out[19]= {1666, 3, 2}

In[20]:= a1 == a3
Out[20]= False

In[21]:= unflattenLeonid[arr_] :=
Partition[Transpose[{arr[[All, {1, 2}]], arr[[All, 3]]}], 3]

In[22]:= (a3 = unflattenLeonid[a2] ;) // Timing

Out[22]= {0.015, Null}

In[23]:= Dimensions[a3]
Out[23]= {1666, 3, 2}

In[24]:= a1 == a3
Out[24]= False

In[25]:= unflattenRay[arr_] :=
Partition[{Most@#, Last@#} & /@ arr, 3]

In[26]:= (a3 = unflattenRay[a2] ;) // Timing
Out[26]= {0.031, Null}

In[27]:= Dimensions[a3]
Out[27]= {1666, 3, 2}

In[28]:= a1 == a3
Out[28]= False

In[29]:= unflattenChris[arr_] := {{#1, #2}, #3} & @@@ # & /@
Partition[arr, 3]

In[30]:= (a3 = unflattenChris[a2] ;) // Timing

Out[30]= {0.031, Null}

In[31]:= Dimensions[a3]
Out[31]= {1666, 3, 2}

In[32]:= a1 == a3
Out[32]= False

In[33]:= unflattenMukasa[arr_] :=
Partition[{Most[#], Last[#]} & /@ arr, 3]

In[34]:= (a3 = unflattenMukasa[a2] ;) // Timing
Out[34]= {0.047, Null}

In[35]:= Dimensions[a3]
Out[35]= {1666, 3, 2}

In[36]:= a1 == a3
Out[36]= False

Thanks again for your help.

--
Valeri

Sseziwa Mukasa

unread,
Oct 2, 2010, 5:45:49 AM10/2/10
to
Here's a faster approach:

In[63]:= First[Timing[
Partition[ArrayFlatten[{{Transpose[{a4[[All, ;; 2]]}], a4[[All, {3}]]}}],
3];]]
Out[63]= 0.118238

On Oct 1, 2010, at 5:43 AM, Sseziwa Mukasa wrote:

>
> On Sep 30, 2010, at 4:52 AM, Valeri Astanoff wrote:
>

Ray Koopman

unread,
Oct 3, 2010, 3:38:38 AM10/3/10
to
On Oct 2, 2:45 am, Valeri Astanoff <astan...@gmail.com> wrote:
>
> Good day,
>
> I have to apologize for not being very clear about what I wanted.
> Seems that you, Bob, were the only one to understand what I meant.
> [I had to replace SplitBy with Split cause I only have version 6]
> Any way I have to thank everyone who tried and help me.
> Maybe this test will more explicit than my poor previous example :
> [...]

I think I understand now what you're doing.

In[1]:= Dimensions[a1 = Table[{{x,y}, RandomInteger[99]},
{x, 0, 99}, {y, 0, 99}]]
Out[1]= {100, 100, 2}

In[2]:= Dimensions[a2 = Flatten /@ Flatten[a1, 1]]

Out[2]= {10000, 3}

In[3]:= unflatten[arr : {{_, _, _} ..}] := Module[{f},


Scan[(f[#[[1]], #[[2]]] = #[[3]]) &, arr];
Table[{{x, y}, f[x, y]},
{x, arr[[All, 1]] // Union},
{y, arr[[All, 2]] // Union}]]

In[4]:= {Timing@Dimensions[a3 = unflatten[a2]], a3 == a1}

Out[4]= {{1.24, {100, 100, 2}}, True}

In[5]:= unflattenBob[arr : {{_, _, _} ..}] := Split[
{Most[#],Last[#]}& /@ arr, #1[[1,1]] == #2[[1,1]] &]

In[6]:= {Timing@Dimensions[a3 = unflattenBob[a2]], a3 == a1}

Out[6]= {{0.12, {100, 100, 2}}, True}

In[7]:= unflattenRay[arr_] := Partition[Transpose@
{arr[[All,{1,2}]],arr[[All,3]]},Length@Union@arr[[All,2]]]

In[8]:= {Timing@Dimensions[a3 = unflattenRay[a2]], a3 == a1}

Out[8]= {{0.02, {100, 100, 2}}, True}

Valeri Astanoff

unread,
Oct 3, 2010, 5:41:16 AM10/3/10
to
On 3 oct, 09:38, Ray Koopman <koop...@sfu.ca> wrote:
> On Oct 2, 2:45 am, Valeri Astanoff <astan...@gmail.com> wrote:
>
>
>
> > Good day,
>
> > I have to apologize for not being very clear about what I wanted.
> > Seems that you, Bob, were the only one to understand what I meant.
> > [I had to replace SplitBy with Split cause I only have version 6]
> > Any way I have to thank everyone who tried and help me.
> > Maybe this test will more explicit than my poor previous example :
> > [...]
>
> I think I understand now what you're doing.
>
> In[1]:= Dimensions[a1 = Table[{{x,y}, RandomInteger[99]},
> {x, 0, 99}, {=

y, 0, 99}]]
> Out[1]= {100, 100, 2}
>
> In[2]:= Dimensions[a2 = Flatten /@ Flatten[a1, 1]]
>
> Out[2]= {10000, 3}
>
> In[3]:= unflatten[arr : {{_, _, _} ..}] := Module[{f},
> Scan[(f[#[[1]], #[[2]]] = #[[3]]) &, arr];
> Table[{{x, y}, f[x, y]},
> {x, arr[[All, 1]] // Union},
> {y, arr[[All, 2]] // Union}]]
>
> In[4]:= {Timing@Dimensions[a3 = unflatten[a2]], a3 == a1}
>
> Out[4]= {{1.24, {100, 100, 2}}, True}
>
> In[5]:= unflattenBob[arr : {{_, _, _} ..}] := Split[
> {Most[#],Last[#]}& /@ arr, #1[[1,1]] == #2[[1,1]] =

&]
>
> In[6]:= {Timing@Dimensions[a3 = unflattenBob[a2]], a3 == a1}
>
> Out[6]= {{0.12, {100, 100, 2}}, True}
>
> In[7]:= unflattenRay[arr_] := Partition[Transpose@
> {arr[[All,{1,2}]],arr[[All,3]]},Length@Union@arr[[All,=

2]]]
>
> In[8]:= {Timing@Dimensions[a3 = unflattenRay[a2]], a3 == a1}
>
> Out[8]= {{0.02, {100, 100, 2}}, True}

Good day,

My "unflatten" was a tortoise, your own is a hare !
This is going to be very useful.
Many thanks (to you and other posters).
--
Valeri

0 new messages