6
$\begingroup$

I am looking for something better than

Select[Map[f,a],test]

As Map will work over the entire association (a) and then Select will work over all of the results. Something like

Cases[a,x_/;test[f[x]]:>f[x]]

But Cases only returns values (or functions of the values) not the keys. I also tried

Map[If[test[#],#]&,a]

But it keeps the keys that fail the test and maps them to Null.

My sample association is

a = <|"a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4, "e" -> 5|>;

I would like to do something like

Select[Map[(3^#-2)&,a],PrimeQ]

Giving

<|b->7,d->79,e->241|>

My actual case is much more complicated but if I have a way to Map and Select in one pass for this case it will solve my more difficult problem. Thanks!

$\endgroup$
  • $\begingroup$ Could you explicitly add what you would like the result of the operation to be? I.e. Show the association you would like to get in the end in your simple result. $\endgroup$ – MarcoB Mar 26 '16 at 12:00
  • 2
    $\begingroup$ You could perhaps make use of AssociationMap: it will map a function over an association like Map, but the function will be given the whole key -> value sequence as an argument. Alternatively, in your If attempt, you could explicitly return Missing[] when the test fails, then clean up the results by running DeleteMissing on the results, which will remove such key -> Missing[] entries from your association. $\endgroup$ – MarcoB Mar 26 '16 at 12:10
  • $\begingroup$ What is wrong with this? "Map will work over the entire association (a) and then Select will work over all of the results." Is it about memory efficiency? If you want to only build the result element by element, some contortion like Reap[Do[If[test@f@Lookup[ass, x], Sow[x -> f@Lookup[ass, x]]], {x, Keys@ass}]][[2, 1]] // Association might help. $\endgroup$ – The Vee Mar 26 '16 at 12:27
  • $\begingroup$ Also, +1 for AssociationMap. Occurrences of Missing[] will not clog the intermediate result too much either as they would all refer to a single instance of the object. $\endgroup$ – The Vee Mar 26 '16 at 12:29
  • $\begingroup$ @TheVee, Yes, AssociationMap will work fine for my application. I can map all of the delete cases to a single key-value pair that is easily and quickly removed (or ignored). $\endgroup$ – JJM Mar 26 '16 at 12:42
6
$\begingroup$

The use of AssociationMap solves the problem in this case as it can map all of the deleted cases to a single key-value pair that is easily removed or ignored.

a = AssociationMap[If[PrimeQ[x = (3^#[[2]] - 2)], #[[1]] -> x, "XXX" -> 0] &, a]

giving

<|XXX->0,b->7,d->79,e->241|>

Then, if needed

KeyDropFrom[a, "XXX"]

giving

<|b->7,d->79,e->241|>

Thanks for the suggestions.

$\endgroup$
  • 4
    $\begingroup$ You might want to use Module to localize the definition of x and avoid potential naming conflicts, i.e., a = Module[{x}, AssociationMap[If[PrimeQ[x = (3^#[[2]] - 2)], #[[1]] -> x, "XXX" -> 0] &, a]] $\endgroup$ – Bob Hanlon Mar 26 '16 at 12:58
  • 1
    $\begingroup$ @JMM, a = AssociationMap[If[PrimeQ[x = (3^#[[2]] - 2)], #[[1]] -> x, Nothing] &, a] $\endgroup$ – garej Mar 26 '16 at 20:24
  • $\begingroup$ @garej, Yes, nothing is better than Nothing! $\endgroup$ – JJM Mar 27 '16 at 13:08
3
$\begingroup$
Association @ KeyValueMap[If[PrimeQ[3^#2 - 2], Nothing, #1 -> #2] &, a]

<|"b" -> 7, "d" -> 79, "e" -> 241|>

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