9
$\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$
  • $\begingroup$ KeyValueMap[#->{#2,#}&]@dat? $\endgroup$ – kglr Jan 23 '18 at 12:20
  • $\begingroup$ Thanks, @kglr . But it will drop the keys as well. $\endgroup$ – sunt05 Jan 23 '18 at 12:21
  • 2
    $\begingroup$ Association@@(KeyValueMap[#->{#2,#}&]@dat)? $\endgroup$ – kglr Jan 23 '18 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 '18 at 13:00
  • $\begingroup$ @sunt05, I think your last key-value should be "c"->{{2, 3}, "c"} $\endgroup$ – alancalvitti May 29 at 20:37
6
$\begingroup$

Using MapIndexed:

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

(* <|"a" -> {2, "a"}, "b" -> {"y", "b"}, "c" -> {{2, 3}, "c"}|> *)
$\endgroup$
  • $\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 '18 at 17:18
6
$\begingroup$
Association @@ (KeyValueMap[# -> {#2, #}&] @ dat) // Normal

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

$\endgroup$
5
$\begingroup$

Another possibility is:

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

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

$\endgroup$
2
$\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$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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