8
$\begingroup$

I have some group of data with different classes,in the form of below:

{{2, 3} -> 1, {1, 5} -> 1, {1, 1} -> 2, {2, 2} -> 2}

I need to merge the data of same class.Like this:

{1->{ {2,3},{1,5}},2->{{1,1},{2,2}} }

Merge[#[[2]] -> #[[1]] & /@ a, List] This doesn't work well.

$\endgroup$
6
  • $\begingroup$ First, apply Association to your data, then use GroupBy[Identity]. $\endgroup$ May 8, 2017 at 14:36
  • 2
    $\begingroup$ Normal[GroupBy[list, Last->First]] $\endgroup$
    – TheYeda
    May 8, 2017 at 14:37
  • $\begingroup$ @erow, Merge[#[[2]] -> #[[1]] & /@ a, Apply@List] $\endgroup$
    – garej
    May 8, 2017 at 14:55
  • 1
    $\begingroup$ Is this close enough to be a duplicate? Gathering of list $\endgroup$
    – Kuba
    May 8, 2017 at 18:19
  • $\begingroup$ You did not explain why the Merge you show did not work well. To get the exact output you show, use Merge[Reverse /@ a, Identity], with Normal applied to the result. The GroupBy approach of @TheYeda is likely to be (much) faster though. $\endgroup$
    – Szabolcs
    May 8, 2017 at 22:35

5 Answers 5

11
$\begingroup$

Using the straightforward way GroupBy

Normal@GroupBy[{{2, 3} -> 1, {1, 5} -> 1, {1, 1} -> 2, {2, 2} -> 2}, Last -> First]

(* {1 -> {{2, 3}, {1, 5}}, 2 -> {{1, 1}, {2, 2}}} *)

Using SequenceCases:

list = {{2, 3} -> 1, {1, 5} -> 1, {1, 1} -> 2, {2, 2} -> 2};
Map[# -> SequenceCases[list, {pat : PatternSequence[_ -> #]} :> First@pat] &, 
Union@list[[All, 2]]]

(* {1 -> {{2, 3}, {1, 5}}, 2 -> {{1, 1}, {2, 2}}} *)

Using pattern in ReplaceRepeated (this will work if at most two entries per index i.e. 1 -> or 2 -> are present)

{{2, 3} -> 1, {1, 5} -> 1, {1, 1} -> 2, {2, 2} -> 2} //. {w___, pat1_ -> x_,
y___, pat2_ -> x_, z___} :> {w, x -> {pat1, pat2} y, z}

(* {1 -> {{2, 3}, {1, 5}}, 2 -> {{1, 1}, {2, 2}}} *)

More general form of ReplaceRepeated (works with more than two entries)

list= {{2, 3} -> 2, {1, 5} -> 1, {1, 1} -> 2, {2, 2} -> 1, {3, 3} -> 2};

list//. {{w___, pat1_ -> x_, y___, pat2_ -> x_, z___} :> {w, x -> {pat1, pat2}, y, z},
{w___, x_ -> {pat1 : {__} ..}, y___, pat2_ -> x_, z___} :> {w, x -> {pat1, pat2}, y, z}}

(* {2 -> {{2, 3}, {1, 1}, {3, 3}}, 1 -> {{1, 5}, {2, 2}}} *)
$\endgroup$
2
  • $\begingroup$ It's hard to understand. $\endgroup$
    – erow
    May 9, 2017 at 4:54
  • $\begingroup$ @erow use the straightforward way for now. As you will explore some aspects of the language more (patterns and rules etc..) I am sure the two methods will fall into place. The purpose here is to show that there are multiple ways of achieving the task. $\endgroup$
    – Ali Hashmi
    May 9, 2017 at 8:06
6
$\begingroup$
data = {{2, 3} -> 1, {1, 5} -> 1, {1, 1} -> 2, {2, 2} -> 2};

#[[1, -1]] -> #[[All, 1]] & /@ GatherBy[data, Last]

(*  {1 -> {{2, 3}, {1, 5}}, 2 -> {{1, 1}, {2, 2}}}  *)
$\endgroup$
6
$\begingroup$
a = {{2, 3} -> 1, {1, 5} -> 1, {1, 1} -> 2, {2, 2} -> 2}

Merge[Reverse /@ a, Apply[List]]
$\endgroup$
5
$\begingroup$

In:

xss = {{2, 3} -> 1, {1, 5} -> 1, {1, 1} -> 2, {2, 2} -> 2};
(*Method 1*)
xss // Map[Reverse] // Merge[#, Join] & // Normal

(*Method 2*)
values = Last /@ xss // Union;
positions[x_] := Position[SparseArray[xss] // Normal, x]
valueToRule[x_] := Rule[x, positions[x]]
values // Map[valueToRule]

Out:

{1 -> {{2, 3}, {1, 5}}, 2 -> {{1, 1}, {2, 2}}}
{1 -> {{1, 5}, {2, 3}}, 2 -> {{1, 1}, {2, 2}}}
$\endgroup$
4
$\begingroup$
data = {{2, 3} -> 1, {1, 5} -> 1, {1, 1} -> 2, {2, 2} -> 2};
data1 = data /. ({x_, y_} -> z_) -> {z -> {x, y}};
Merge[Flatten[Tally[data1][[All, 1]]], Identity]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.