# Summarize a list of pairs / (Using GatherBy and Tally?)

Given a list of (frencuently repeated and unsorted) pairs

{Mode, SubMode}

I want to form the list

{ {COUNT_mode1, COUNT_mode2,...,COUNT_modeN}, {COUNT_mode1_submode1, COUNT_mode1,submode2, ... , COUNT_mdoe1,submodeM1, ... ,COUNT_modeN_submodeNM}, {mode1,mode2,...}, {submode1,submode2,...} }

Here is an example, given:

l = { {"games","minecraft"},{"games","minecraft"},{"games","WoW"}, {"books","book1"},{"books","book1"},{"books","book1"},{"books","book5"},{"other","something"},{"other","book1"}}

MyFunction[l] -->
{
{3,4,2},
{2,1,3,1,1,1},
{"games","books","other"},
{"minecraft","WoW","book1","book5","something","book1"}
}

• I notice that you did not Accept an answer to this question. Is there something that remains to be addressed? Oct 18, 2014 at 22:32
• @Mr.Wizard I forgot to accept one. Oct 20, 2014 at 7:59

Update: cleaner now and with a v10 alternative.

If I am understanding you I think I would use:

Flatten[Reverse[Tally /@ (l\[Transpose]), 3], {3, 1}]

{
{3, 4, 2},
{2, 1, 3, 1, 1, 1},
{"games", "books", "other"},
{"minecraft", "WoW", "book1", "book5", "something", "book1"}
}


Alternatively using Counts introduced in Mathematica 10:

Join[Values, Keys][Counts /@ (l\[Transpose])] // Through


Here is one way.

modes = Transpose[Tally[l[[All, 1]]]]

(* Out[176]= {{"games", "books", "other"}, {3, 4, 2}} *)

submodes =
Reverse[Transpose[
Flatten[Map[Tally, GatherBy[l, First][[All, All, 2]]], 1]]]

(* Out[178]= {{2, 1, 3, 1, 1, 1}, {"minecraft", "WoW", "book1", "book5",
"something", "book1"}} *)

Riffle[modes, submodes]

(* Out[179]= {{"games", "books", "other"}, {2, 1, 3, 1, 1, 1}, {3, 4,
2}, {"minecraft", "WoW", "book1", "book5", "something", "book1"}} *)


It clunks a bit, but it generates the specified output for the test input you provided.

summarize[pairs_] :=
With[{gathered = GatherBy[pairs, First]},
{Length /@ gathered,
Flatten[Tally[#[[All, -1]]][[All, -1]] & /@ gathered],
gathered[[All, 1, 1]],
Flatten[DeleteDuplicates /@ gathered[[All, All, -1]], 1]
}];

summarize[l] === {{3, 4, 2}, {2, 1, 3, 1, 1, 1}, {"games", "books", "other},
{"minecraft", "WoW", "book1", "book5", "something", "book1"}}

(* True *)


Here is one way.

MyFunc[l_] := Block[{t1, t2, res},
t1 = Tally[l[[All, 1]]];
t2 = Tally[l[[All, 2]]];
res = {t1[[All, 2]], t2[[All, 2]], t1[[All, 1]], t2[[All, 1]]};
Return[res];
];

• I'd advise against using Block for variable localization. Module is much safer. Apr 17, 2014 at 9:22

An approach using Reap and Sow:

Using:

lst = {{"games", "minecraft"}, {"games", "minecraft"}, {"games",
"WoW"}, {"books", "book1"}, {"books", "book1"}, {"books",
"book1"}, {"books", "book5"}, {"other", "something"}, {"other",
"book1"}}


Then

Join[Transpose[
Last@Reap[Sow[1, First[#]] & /@ lst, _, {Total@#2, #1} &]],
Transpose@
Last@Reap[
Sow[1, wp[#]] & /@ lst, _, {Total@#2, #1[[1, 2]]} &]][[{1, 3, 2,
4}]]


yields:

{{3, 4, 2}, {2, 1, 3, 1, 1, 1}, {"games", "books",
"other"}, {"minecraft", "WoW", "book1", "book5", "something",
"book1"}}