Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

The documentation for associations says that the keys of an association are transparent for many operations. Map is one such operation. However, I am confronted with something a bit unexpected.

Clear[a, f];

a = <|1 -> <|2 -> {{6, 8}, {6, 10}}|>, 6 -> <|8 -> {{14, 18}, {2, 4}}|>|>;

f = Select[#[[2]] >= 10 &] @ # &;

f /@ a (* <|1 -> <| |>, 6 -> <| |>|> *)

f @ {{6, 8}, {6, 10}} (* {{6, 10}} *)

f @ {{14, 18}, {2, 4}} (* {{14, 18}} *)

I don't understand why f applied individually to the arguments produces the desired result, but when mapped over those same arguments inside the association, does not. What is the error in my thinking?

Thank you in advance for your help.

share|improve this question

1 Answer 1

up vote 6 down vote accepted

First, your construction of f is a bit malformed. You are using the operator form of Select, therefore the Select expression itself acts as a function; you do not need to add @# & to it. Use instead:

f = Select[#[[2]] >= 10 &];

The reason that your operations are not the same can be seen by mapping a dummy function foo:

foo /@ a
<|1 -> foo[<|2 -> {{6, 8}, {6, 10}}|>], 6 -> foo[<|8 -> {{14, 18}, {2, 4}}|>]|>

Because you have nested Assocations in a the function is applied to an Association rather than a List as I think you expect. We can see that simple function application does not "go inside" Association:

foo[<|2 -> {{6, 8}, {6, 10}}|>]
foo[<|2 -> {{6, 8}, {6, 10}}|>]

Depending on what you want you may be able to write simply:

Map[f] /@ a
<|1 -> <|2 -> {{6, 10}}|>, 6 -> <|8 -> {{14, 18}}|>|>

However if you want this selection to work on arbitrarily nested Associations you will need something else. One solution is this abstraction that threads a function over Association expressions:

(p : valueMap[fn_])[a_Association] := p /@ a
valueMap[fn_][other_]              := fn @ other

Now:

a2 = Append[a, 7 -> {{10, 20}, {1, 2}}];

a2 // valueMap[f]
<|1 -> <|2 -> {{6, 10}}|>, 6 -> <|8 -> {{14, 18}}|>, 7 -> {{10, 20}}|>
share|improve this answer
    
Thank you for the excellent answer. –  Shredderroy Sep 15 at 7:30
    
@Shredderroy You're welcome. I added an abstraction (valueMap) that simplifies the application to arbitrarily nested Associations. –  Mr.Wizard Sep 15 at 7:39

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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