# Assigning sections of a matrix to lists based on row value

I'm working with a very large (4x41355) matrix and I'm trying to make lists out of sections of rows based on the value in the fourth row. It's like this:

{{p1, p2, p3,...,p41355},{x1, x2, x3,...,x41355},{y1,y2,y3,...,y41355},{1,1,1,...,613}}


I'm looking for a way to make lists for x and y based on the fourth row. So all x values that have a 1 in the fourth row are assigned to a list (for a total of 613 lists), and then do the same for y values (for another 613 lists).

I really have no idea how to approach this, answers much appreciated.

Edit: I'll try to give an example with a smaller matrix.

{{x1, x2, x3, x4, x5, x6},{y1, y2, y3, y4, y5, y6},{1, 1, 1, 1, 2, 2}}


What I would want from this would be:

xlist1={x1, x2, x3, x4}
xlist2={x5, x6}

ylist1={y1, y2, y3, y4}
ylist2={y5, 56}

• Can you give a small example where you give a small version of the list with the expected output? It's a little unclear what you mean, actually, by row, why there are 613 lists, etc. Commented Nov 19, 2015 at 21:43
• Welcome to Mathematica.SE! I suggest the following: 0) Browse the common pitfalls question 1) As you receive help, try to give it too, by answering questions in your area of expertise. 2) Read the faq! 3) When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign! Commented Nov 19, 2015 at 22:10

list = {{x1, x2, x3, x4, x5, x6}, {y1, y2, y3, y4, y5, y6}, {1, 1, 1, 1, 2, 2}};

tra = Transpose[{#, Last@list}] & /@ Most@list;

{xlist1, ylist1, xlist2, ylist2} =
(Cases[#, {a_, 1} -> a] & /@ tra)~Join~(Cases[#, {a_, 2} -> a] & /@ tra)


{{x1, x2, x3, x4}, {y1, y2, y3, y4}, {x5, x6}, {y5, y6}}

l = {{x1, x2, x3, x4, x5, x6}, {y1, y2, y3, y4, y5, y6}, {1, 1, 1, 1, 2, 2}}
Transpose[Most /@ Transpose /@ GatherBy[Transpose@l, Last]]

(*{{{x1, x2, x3, x4}, {x5, x6}}, {{y1, y2, y3, y4}, {y5, y6}}}*)


Here is a solution which makes use of a tail-recursive function. It is somewhat more complex than any of the other answers because it handles cases where the data is ragged.

splitter[{}, _, new_] := List @@ Flatten @ new;
splitter[_, {}, new_] := List @@ Flatten @ new;
splitter[old : {__}, runs : {__}, new_: tmp[]] :=
Module[{car, cdr},
{car, cdr} = TakeDrop[old, UpTo[First[runs]]];
splitter[cdr, Rest[runs], tmp[new, car]]]


splitter applied to the example given in the question

example = {{x1, x2, x3, x4, x5, x6}, {y1, y2, y3, y4, y5, y6}, {1, 1, 1, 1, 2, 2}};
{vals, {tags}} = TakeDrop[example, 2];
With[{runs = Length /@ Split[tags]}, splitter[#, runs] & /@ vals]


{{{x1, x2, x3, x4}, {x5, x6}}, {{y1, y2, y3, y4}, {y5, y6}}}

Now I generate data that is complex enough to show splitter's behavior with ragged data.

SeedRandom[1];
runList = Flatten @ Table[ConstantArray[i, RandomInteger[{1, 5}]], {i, 5}]
data = Table[RandomInteger[{1, 99}, Length@runList], {2}]

{1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 5, 5}
{{97, 9, 49, 64, 41, 29, 67, 93, 32, 9, 77, 90, 34, 1, 77, 76},
{43, 57, 97, 20, 39, 4, 22, 80, 58, 30, 41, 88, 6, 73, 68, 41}}


With arrays of the same length:

With[{runs = Length /@ Split[runList]}, splitter[#, runs] & /@ data]

{{{97, 9, 49, 64, 41}, {29, 67, 93}, {32, 9, 77, 90, 34}, {1}, {77, 76}},
{{43, 57, 97, 20, 39}, {4, 22, 80}, {58, 30, 41, 88, 6}, {73}, {68, 41}}}


With five elements clipped off the end of each row of data:

With[{runs = Length /@ Split[runList]}, splitter[#, runs] & /@ data[[All, ;; -6]]]

{{{97, 9, 49, 64, 41}, {29, 67, 93}, {32, 9, 77}},
{{43, 57, 97, 20, 39}, {4, 22, 80}, {58, 30, 41}}}


With two elements clipped off the end of runList:

With[{runs = (Length /@ Split[runList])[[;; -3]]}, splitter[#, runs] & /@ data]

{{{97, 9, 49, 64, 41}, {29, 67, 93}, {32, 9, 77, 90, 34}},
{{43, 57, 97, 20, 39}, {4, 22, 80}, {58, 30, 41, 88, 6}}}