9
$\begingroup$

I apologise in advance if this is a duplicate. I have looked at this question, yet have been unable to figure out how to use it when it's not nested: Link. I have a grouped list of random words

    list = <|"Net1" -> {{"counteroffensive", "nonpayment", 
     "dieresis"}, {"suffragan", "identifiably"}}, 
  "Net2" -> {{"psychiatrist", "pusher", "generous", "praising", 
     "thy"}, {"amplification", "amylase", "shooting", "tumbler", 
     "mimosa", "dengue"}}|>

And the output should be:

    output = {
<|"Net1" -> {"counteroffensive", "nonpayment", 
     "dieresis"}|>, 
<|"Net1" -> {"suffragan", 
     "identifiably"}|>, 
<|"Net2" -> {"psychiatrist", "pusher", 
     "generous", "praising", "thy"}|>, 
<|"Net2" -> {"amplification", 
     "amylase", "shooting", "tumbler", "mimosa", "dengue"}|>}

Much appreciated for your help

$\endgroup$

6 Answers 6

7
$\begingroup$
KeyValueMap[Thread[#1 -> #2] &, list] // Flatten // Map[Association]
$\endgroup$
4
$\begingroup$
Association /@ Flatten[Table[Thread[key -> list[key]], {key, Keys[list]}], 1]
$\endgroup$
4
$\begingroup$

You can use AssociationTranspose,

Needs["GeneralUtilities`"]
AssociationTranspose[list]
(* 
    {
        <|
            "Net1" -> {"counteroffensive", "nonpayment", "dieresis"},
            "Net2" -> {"psychiatrist", "pusher", "generous", "praising", "thy"}
        |>,
        <|
            "Net1" -> {"suffragan", "identifiably"},
            "Net2" -> {"amplification", "amylase", "shooting", "tumbler", "mimosa", "dengue"}
        |>
    }
*)

which is very close to the output desired in the OP.

$\endgroup$
4
$\begingroup$

Using ideas from this answer by Leonid:

unMerge = Catenate @* MapIndexed[Association /@ Thread[#2[[1, 1]] -> #] &];

unmerged = unMerge @ list

{<|"Net1" -> {"counteroffensive", "nonpayment", "dieresis"}|>,
<|"Net1" -> {"suffragan", "identifiably"}|>,
<|"Net2" -> {"psychiatrist", "pusher", "generous", "praising", "thy"}|>,
<|"Net2" -> {"amplification", "amylase", "shooting", "tumbler", "mimosa", "dengue"}|>}

Merge[Identity] @ unmerged  == list

True

Another way to use MapIndexed:

unMerge2 = Map[Association] @* Catenate @* MapIndexed[Thread[#2[[1, 1]] -> #] &];

unMerge @ list == unMerge2 @ list

True

Also:

unMerge3 = Query[Catenate @* Map[KeyValueMap[Association @* Rule]] @* Transpose];

Sort @ unMerge @ list == Sort @ unMerge3 @ list

True

If the output from GeneralUtilities`AssociationTranspose is acceptable, you can also use:

Query[Transpose] @ list

{<|"Net1" -> {"counteroffensive", "nonpayment", "dieresis"}, "Net2" -> {"psychiatrist", "pusher", "generous", "praising", "thy"}|>,
<|"Net1" -> {"suffragan", "identifiably"}, "Net2" -> {"amplification", "amylase", "shooting", "tumbler", "mimosa", "dengue"}|>}

$\endgroup$
2
  • 1
    $\begingroup$ Curry can make Query example more concise; Query[KeyValueMap[Curry[Association@*Rule, 2]@# /@ #2 &] /* Catenate]@list . $\endgroup$
    – Edmund
    Commented Jan 3, 2020 at 1:33
  • $\begingroup$ Thank you @Edmund; that's much nicer. $\endgroup$
    – kglr
    Commented Jan 3, 2020 at 1:55
3
$\begingroup$

Shortest yet?

<|#|> & /@ Join @@ Thread /@ Normal[list]
$\endgroup$
2
$\begingroup$

If you don't care about key order, transposing a Dataset gives you what you want, it just needs a catenation of association rules and transforming it back to list with Normal:

Dataset[list][Transpose /* Normal /* Catenate] // Normal
$\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.