# Use a categorical argument to add one layer of list structure

Consider the following nested list

x = {{1,2,a}, {3,4,a}, {8,11,b}, {12,3,a}, {4,3,b}, {3,2,c}}


I want to use the categorical variable [a,b,c] in order to group the above sublists (resulting in a list with "3 degrees of nestedness"). For the above example the goal is to obtain:

{ { {1,2},{3,4},{12,3} }, { {8,11},{4,3} }, {3,2} }


, where the first nested sublist is the group of sublists in x that contained the argument a, the second nested sublist is the group of sublists in x that contained the argument b and the third sublist is the group of sublists in x that contained the argument c

## 4 Answers

x = {{1, 2, a}, {3, 4, a}, {8, 11, b}, {12, 3, a}, {4, 3, b}, {3, 2, c}};

f = Map[Most, GatherBy[#, Last], {2}] &;
(* or f = Most /@ # & /@ GatherBy[#, Last] & *)

f@x
(* {{{1,2},{3,4},{12,3}},{{8,11},{4,3}},{{3,2}}} *)


or

f2 = Map[Most, SplitBy[SortBy[#, Last], Last], {2}] &;
(* or f2 = Map[Most, SplitBy[#[[Ordering[Last /@ #]]], Last], {2}] &; *)

f2@x
(* {{{1,2},{3,4},{12,3}},{{8,11},{4,3}},{{3,2}}} *)


Note: Under this method, the ordering of the elements within each category may change (thanks: @Michael E2).

Version 10:

f3 = Values@GroupBy[#, Last->Most]&
f3@x
(*  {{{1,2},{3,4},{12,3}},{{8,11},{4,3}},{{3,2}}} *)

• Note that the two methods are not strictly equivalent. (E.g., try x = {{3, 4, a}, {1, 2, a}, {8, 11, b}, {12, 3, a}, {4, 3, b}, {3, 2, c}}, in which the elements are not ordered by the secondary criteria used by SortBy.) (+1) – Michael E2 Dec 4 '14 at 19:59
• @MichaelE2, good point. I updated with a note. – kglr Dec 4 '14 at 20:11
groupCategorically[ll_List, keys_List] :=
keys /. GroupBy[ll, Last] /. Thread[keys :> Sequence[]]


Example:

groupCategorically[{{1, 2, a}, {3, 4, a}, {8, 11, b}, {12,
3, a}, {4, 3, b}, {3, 2, c}}, {a, b, c}]

(* Out[156]= {{{1, 2}, {3, 4}, {12, 3}}, {{8, 11}, {4, 3}}, {{3, 2}}} *)

f[l_List, cats_List] := Cases[l, p : {__, #} :> Most@p] & /@ cats
f[x, {a, b, c}]
(* {{{1, 2}, {3, 4}, {12, 3}}, {{8, 11}, {4, 3}}, {{3, 2}}} *)


It will ignore the "categorical" variables not included:

f[x, {a, b}]
(* {{{1, 2}, {3, 4}, {12, 3}}, {{8, 11}, {4, 3}}}*)

DeleteCases[GatherBy[x, Last], _Symbol, -1]
(*{{{1, 2}, {3, 4}, {12, 3}}, {{8, 11}, {4, 3}}, {{3, 2}}}*)