5
$\begingroup$

Given the following MWE, where:

lst = {<|"a" -> 1, "b" -> 2|>,
   <|"a" -> 2, "b" -> 2|>,
   <|"a" -> 3, "b" -> 2|>,
   <|"a" -> 4, "b" -> 2|>,
   <|"a" -> 5, "b" -> 2|>};

and the problem is that:

if the value of a is greater than 3 then "c"-> True must be added to the association.

I have the following =working= code

Map[If[#[[1]] > 3, var = #; AssociateTo[var, "c" -> True], #] &, lst]

which yields:

{<|"a" -> 1, "b" -> 2|>, 
<|"a" -> 2, "b" -> 2|>, 
<|"a" -> 3, "b" -> 2|>, 
<|"a" -> 4, "b" -> 2, "c" -> True|>, 
<|"a" -> 5, "b" -> 2, "c" -> True|>}

I prefer If-less programming and the var=# looks so unnecessary.

Is there a more "elegant" solution to this problem?

$\endgroup$
3
  • 1
    $\begingroup$ It would appear that you can add keys with at least Join, Append, Prepend, <|..., key -> val|>. I guess this was your real question. $\endgroup$
    – Szabolcs
    Feb 10, 2017 at 9:56
  • 1
    $\begingroup$ Related: (51472) $\endgroup$
    – Mr.Wizard
    Feb 10, 2017 at 10:17
  • $\begingroup$ That's quite an interesting question/answers-set. $\endgroup$ Feb 10, 2017 at 14:42

3 Answers 3

10
$\begingroup$

# and If -less approach:

lst /. a : KeyValuePattern["a" -> n_ /; n > 3] :> <|a, "c" -> True|>
$\endgroup$
7
  • $\begingroup$ So there is an If-less version after all. Beautiful code. $\endgroup$ Feb 10, 2017 at 10:01
  • 2
    $\begingroup$ @niloderoock Is If-less a primary metric of success here? $\endgroup$
    – Mr.Wizard
    Feb 10, 2017 at 10:05
  • $\begingroup$ I have this hypothesis that IF's are red flags for poor program design: "When the IF's come in, the quality of software starts to deteriorate." $\endgroup$ Feb 10, 2017 at 10:54
  • $\begingroup$ In refactoring code ( i.e. Java ) I aim to remove all IF's which always leads to cleaner design and code with much less LOC. $\endgroup$ Feb 10, 2017 at 11:17
  • $\begingroup$ Accepted. I didn't even know KeyValuePattern. This function will be of help in a few places of my code. $\endgroup$ Feb 11, 2017 at 9:05
7
$\begingroup$

Terse style:

<|#, If[#a > 3, "c" -> True, {}]|> & /@ lst
{
 <|"a" -> 1, "b" -> 2|>,
 <|"a" -> 2, "b" -> 2|>,
 <|"a" -> 3, "b" -> 2|>,
 <|"a" -> 4, "b" -> 2, "c" -> True|>,
 <|"a" -> 5, "b" -> 2, "c" -> True|>
}

For what it's worth version 10.1 does not have KeyValuePattern, but this works:

lst /. x_ /; x["a"] > 3 :> <|x, "c" -> True|>

And just to play with other methods:

<|#, DeleteCases[<|"c" -> #a > 3|>, False]|> & /@ lst
$\endgroup$
6
$\begingroup$

I recommend

If[#a > 3, Append[#, "c" -> True], #] & /@ lst

if you can tolerate a bit of If.

$\endgroup$
6
  • $\begingroup$ Yes, me too, too much If though. $\endgroup$
    – Kuba
    Feb 10, 2017 at 9:46
  • $\begingroup$ @Kuba Well, you gave the Ifless version and there were a few small things to improve in the original that may make the If bearable after all. Consider it an alternative. $\endgroup$
    – Szabolcs
    Feb 10, 2017 at 9:48
  • 1
    $\begingroup$ Right. p.s. don't know if better, but shorter: <|#, "c" -> True|> $\endgroup$
    – Kuba
    Feb 10, 2017 at 9:48
  • 1
    $\begingroup$ Sorry, I don't. I'd ask WReach if I'd like to know ;) $\endgroup$
    – Kuba
    Feb 10, 2017 at 9:53
  • 1
    $\begingroup$ Maybe because it is stronger than Flat. It also flattens List's: Association[a->1, {b->2, Association[c->3]}] gives <|a -> 1, b -> 2, c -> 3|>. $\endgroup$ Feb 11, 2017 at 18:41

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.