11
$\begingroup$

Say I have a Dataset like this:

dat=Dataset[<|"a" -> 2, "b" -> "y", "c" -> {2, 3}|>]

I want to get the keys of upper levels as elements in the lower levels, say something like this:

datNeed=Dataset[<|"a" -> {2, "a"}, "b" -> {"y", "b"}, "c" -> {{2, 3}, "c"}|>]

To get datNeed, what query should be performed over dat?

I know KeyValueMap may get something similar but the caveat is that keys will be dropped, which I hope not.

$\endgroup$
6
  • 1
    $\begingroup$ KeyValueMap[#->{#2,#}&]@dat? $\endgroup$
    – kglr
    Jan 23, 2018 at 12:20
  • $\begingroup$ Thanks, @kglr . But it will drop the keys as well. $\endgroup$
    – sunt05
    Jan 23, 2018 at 12:21
  • 3
    $\begingroup$ Association@@(KeyValueMap[#->{#2,#}&]@dat)? $\endgroup$
    – kglr
    Jan 23, 2018 at 12:36
  • $\begingroup$ Thanks @kglr! This works. I was thinking there might be some ascending operations using the Query hack to resolve this. Now it seems not easy to achieve it in the Query way. $\endgroup$
    – sunt05
    Jan 23, 2018 at 13:00
  • $\begingroup$ @sunt05, I think your last key-value should be "c"->{{2, 3}, "c"} $\endgroup$ May 29, 2019 at 20:37

5 Answers 5

10
$\begingroup$

Using MapIndexed:

MapIndexed[{#, #2[[1, 1]]} &, dat] // Normal

(* <|"a" -> {2, "a"}, "b" -> {"y", "b"}, "c" -> {{2, 3}, "c"}|> *)
$\endgroup$
1
  • $\begingroup$ Excellent hack by using MapIndexed! Then it seems this one may elegantly fit into the Query form: dat[MapIndexed[{#, #2[[1, 1]]} &]] $\endgroup$
    – sunt05
    Jan 23, 2018 at 17:18
10
$\begingroup$
Association @@ (KeyValueMap[# -> {#2, #}&] @ dat) // Normal

<|"a" -> {2, "a"}, "b" -> {"y", "b"}, "c" -> {{2, 3}, "c"}|>

$\endgroup$
9
$\begingroup$

Another possibility is:

dat[{Keys, {Values,Keys} /* Thread} /* Apply[AssociationThread]] //Normal

<|"a" -> {2, "a"}, "b" -> {"y", "b"}, "c" -> {{2, 3}, "c"}|>

$\endgroup$
4
$\begingroup$

I have a set of related functions that I use extensively in data work including keyValueMap, which is an operator that lets you pass user defined functions to apply to Keys, Values or both.

apply g to Values:

keyValueMap[Key -> g_][as_Association] := 
   AssociationThread[
    KeyValueMap[List /* First][as] -> KeyValueMap[g][as]]

apply f to Keys:

keyValueMap[f_ -> Value][as_Association] := 
   AssociationThread[
    KeyValueMap[f][as] -> KeyValueMap[List /* Last][as]]

Apple f to Keys, g to Values:

keyValueMap[f_ -> g_][as_Association] := 
   AssociationThread[KeyValueMap[f][as] -> KeyValueMap[g][as]]

Here Key and Value are just symbolic placeholders, slightly more mnemonic than using Identity, (can Blank be used instead?)

In your application, use:

dat[keyValueMap[Key -> List /* Reverse]]  (* Normal *)

<|"a" -> {2, "a"}, "b" -> {"y", "b"}, "c" -> {{2, 3}, "c"}|>

or simply List if order is not important.

To motivate the discussion, additional operators can be defined using keyValueMap above. For example keySubKeyMap with the following application:

Suppose the Values are themselves nested Associations. How to Map a function combining upper level Keys with those at lower level (hence Sub)?

dat2 = Dataset[<|"a" -> <|2 -> 10|>, "b" -> <|"y" -> 11, "z" -> 12|>, 
   "c" -> <|2 -> 13, 3 -> 14|>|>]

Use:

keySubKeyMap[f_] := 
 keyValueMap[
  Key -> List /* Replace[{k_, as_} :> KeyMap[Curry[f, 2][k]][as]]]

Then:

dat2[keySubKeyMap[f]] // Normal

<|"a" -> <|f["a", 2] -> 10|>, "b" -> <|f["b", "y"] -> 11, f["b", "z"] -> 12|>, "c" -> <|f["c", 2] -> 13, f["c", 3] -> 14|>|>

$\endgroup$
0
$\begingroup$
 GroupBy[Normal @ Normal @ dat, First, First @* MapApply[Reverse @* List]]

<|"a" -> {2, "a"}, "b" -> {"y", "b"}, "c" -> {{2, 3}, "c"}|>

$\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.