8
$\begingroup$

Suppose I have a list of rules whose keys are not of identical structure (in my case, the keys are either lists of at least one symbol or symbols alone):

rules = {{a} -> 1, {b, c} -> 1, d -> 2, {e, f} -> 2, {g, g} -> 3, g -> 4};

The aim is to get all keys with matching values grouped together to end up with

newRules = {{a, b, c} -> 1, {d, e, f} -> 2, {g, g} -> 3, {g} -> 4};

I have what seems to me to be a hacky attempt to do this:

Reverse /@
    Normal[
        Merge[
            Association /@ Reverse /@ rules, Flatten]
        ] == newRules
(* True *)

Are there any better ways to do this?

$\endgroup$
3
  • $\begingroup$ You could use Flatten[#[[;; , 1]]] -> #[[1, 2]] & /@ GatherBy[rules, Last]. $\endgroup$ Commented Jan 4, 2018 at 21:34
  • 1
    $\begingroup$ equally hacky, but different: GroupBy[List @@@ rules, Last -> Most, Flatten] // GeneralUtilities`AssociationInvert $\endgroup$
    – Jason B.
    Commented Jan 4, 2018 at 21:37
  • 1
    $\begingroup$ Reverse[Normal[GroupBy[rules, Last -> First, Flatten]], 2] $\endgroup$
    – Coolwater
    Commented Jan 4, 2018 at 21:56

5 Answers 5

10
$\begingroup$

There are many ways, here's one:

KeyValueMap[#2 -> # &] @ GroupBy[rules, Last -> First, Flatten]
$\endgroup$
7
$\begingroup$
Reverse /@ (Flatten /@ PositionIndex[Association@rules] // Normal) 

{{a, b, c} -> 1, {d, e, f} -> 2, {g, g} -> 3, {g} -> 4}

In addition:

Flatten /@ PositionIndex[Association@rules]

<|1 -> {a, b, c}, 2 -> {d, e, f}, 3 -> {g, g}, 4 -> {g}|>

$\endgroup$
6
$\begingroup$
Reap[Sow @@@ (List @@@ rules), _, Flatten[{#2}] -> #1 &][[-1]]

yields:

{{a, b, c} -> 1, {d, e, f} -> 2, {g, g} -> 3, {g} -> 4}
$\endgroup$
5
$\begingroup$
KeyValueMap[#2 -> #&] @ Merge[Flatten][Reverse /@ rules]

{{a, b, c} -> 1, {d, e, f} -> 2, {g, g} -> 3, {g} -> 4}

Als0

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

{{a, b, c} -> 1, {d, e, f} -> 2, {g, g} -> 3, {g} -> 4}

and

Values @ GroupBy[rules, Last, Flatten @ #[[All, 1]] -> #[[1, -1]]&] 

{{a, b, c} -> 1, {d, e, f} -> 2, {g, g} -> 3, {g} -> 4}

$\endgroup$
2
$\begingroup$
rules = {{a} -> 1, {b, c} -> 1, d -> 2, {e, f} -> 2, {g, g} -> 3, g -> 4};

A variant of 1066's first answer

KeyValueMap[Flatten[#2] -> #1 &, PositionIndex[<|rules|>]]

{{a, b, c} -> 1, {d, e, f} -> 2, {g, g} -> 3, {g} -> 4}

$\endgroup$

Your Answer

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

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