# How to partition a list according to a value in the list

I have a list of the form $\{\{d_1,c_1\},\{d_2,c_2\},\ldots,\{d_n,c_n\}\}$. The values c_i take values between $1,\ldots,k$.

I want to partition the data into $k$ lists according to the values $c_i$.

For example, if we have $\{\{d_1,2\},\{d_2,3\},\{d_3,1\},\{d_4,2\},\{d_5,1\},\{d_6,1\}\}$, I would get a list $\{\{\{d_3,1\},\{d_5,1\},\{d_6,1\}\},\{\{d_1,2\},\{d_4,2\}\},\{\{d_2,3\}\}\}$.

How can I achieve this nicely and compactly in Mathematica?

Using Gather:

list = {{"d", 1}, {"b", 2}, {"b", 4}, {"c", 4}, {"b", 3}, {"d", 4}, {"d", 3}, {"d", 2},
{"d", 4}, {"a", 3}};


Then:

Gather[SortBy[list, Last], (Last[#1] === Last[#2]) &]

{{{"d", 1}}, {{"b", 2}, {"d", 2}}, {{"a", 3}, {"b", 3}, {"d", 3}},
{{"b", 4}, {"c", 4}, {"d", 4}, {"d", 4}}}

list = Transpose[{RandomChoice[{"a", "b", "c", "d"}, 10],  RandomInteger[3, 10]}]
(* {{"d",3},{"a",0},{"c",3},{"c",1},{"a",3},{"d",3},{"a",2},{"a",1},{"c",1},{"b",3}}*)

GatherBy[SortBy[list, Last], Last]


or

SplitBy[SortBy[list, Last], Last]


or

Split[SortBy[list, Last], Last@#1 != Last #2 &]


all give

(* {{{"a",0}},
{{"a",1},{"c",1},{"c",1}},
{{"a",2}},{{"a",3},{"b",3},{"c",3},{"d",3},{"d",3}}} *)


Or define a function:

gthrbyF = Fold[#2[#, Last] &, #, {SortBy, GatherBy}] & (* or replace GatherBy with SolitBy *)
gthrbyF @ list
(* same output *)


Update: Further alternatives:

Pick[list, Last /@ list, #] & /@ Sort@DeleteDuplicates[Last /@ list]
Cases[list, {_, #}] & /@ Sort@DeleteDuplicates[Last /@ list]
Function[{a}, Select[list, #[[2]] == a &]] /@ Sort@DeleteDuplicates[Last /@ list]


all give the same output as above except possibly the order of elements in each partition.