5
$\begingroup$

In the same way that Nothing disappears from Lists, is there a built-in that when it appears as the value in an association the whole key/value pair disappears?

In other words, is there something that makes <|a -> 1, b -> associationNothing|> evaluate to <|a->1|>? (Nothing doesn't work for this purpose.)

If there is no equivalent, can we construct one?

$\endgroup$
10
  • 2
    $\begingroup$ I think you will need to apply DeleteCases[#, Nothing] & to the association $\endgroup$
    – Coolwater
    May 6 at 14:58
  • 1
    $\begingroup$ Don't know of anything built in. As for "can we construct one", we can surely do something, but we'd need to know some sample use cases. As it stands right now, we already have Values[<|a -> 1, b -> Nothing|>] giving {1}. And we have <|a -> 1, Nothing|> resolving to <|a -> 1|>. And we have DeleteCases[<|"a" -> 1, "b" -> Nothing|>, Nothing] giving <|"a" -> 1|>. So, in what way are these unsatisfactory for the use cases you envision? $\endgroup$
    – lericr
    May 6 at 15:06
  • 2
    $\begingroup$ <|a -> 1, b -> 2|> // KeyDrop[b] ? $\endgroup$
    – Syed
    May 6 at 15:08
  • 1
    $\begingroup$ @lericr Map[f, <| a->1, b->Nothing |>] gives <|a->f[1], b->f[Nothing]|>, for example. $\endgroup$
    – evanb
    May 6 at 16:30
  • 1
    $\begingroup$ Missing[] as somewhat the role of Nothing for associations in the sense that the heads of the results of <|a -> 1, b -> Missing[]|>[b] and <|a -> 1|>[b] will be the same. And DeleteMissing[<|a -> 1, b -> Missing[]|>[b]] returns <|a -> 1|>[b]. It does not work as desired by OP for Map, though. $\endgroup$ May 7 at 9:52

2 Answers 2

6
$\begingroup$

You could make a symbol that turned any Rule it is part of into Nothing with something like

In[28]:= ClearAll[associationNothing]
associationNothing /: Rule[key_, associationNothing] := Nothing

In[30]:= <|"a" -> 1, "b" -> associationNothing, "c" -> 3|>

Out[30]= <|"a" -> 1, "c" -> 3|>

but this means the substitution happens anywhere, not just in an association:

In[31]:= b -> associationNothing

Out[31]= Nothing

In[32]:= {c -> associationNothing, d, 3}

Out[32]= {d, 3}

If this isn't something you want to happen you could do some shenanigans with the stack to get around the rules for up values:

ClearAll[associationNothing]
associationNothing /: Rule[key_, associationNothing] := Nothing /; MatchQ[
    Stack[], 
    {___, Association, List, associationNothing, RuleCondition, MatchQ}
]

which should meet the requirements:

In[38]:= {c -> associationNothing, <|d -> associationNothing|>, 3}

Out[38]= {c -> associationNothing, <||>, 3}

I think it's crazy, but it just might work.

narrator: it does not work

The above shenanigans only work when constructing an association directly, it does not work when modifying an existing association:

In[49]:= assoc = <|"a" -> 1, "b" -> associationNothing, "c" -> 1|>

Out[49]= <|"a" -> 1, "c" -> 1|>

In[50]:= assoc["d"] = associationNothing

Out[50]= associationNothing

In[51]:= assoc

Out[51]= <|"a" -> 1, "c" -> 1, "d" -> associationNothing|>

I don't know a way around this.

$\endgroup$
4
$\begingroup$

Nothing inside a List evaluates to Sequence[] and thus vanishes completely from the arguments of List. One could emulate this behavior by replacing y_->Nothing with Sequence[] in the arguments of Association. Doing this manually by applying a function to a given Association would be one option another one (which I am hesitant to present but I am doing it anyway) is to modify Association itself to do this automatically:

Unprotect[Association]
Association[x___]:=Association@@(List[x]//.{a___,y_->Nothing,b___}:>List[a,b])/;MatchQ[List[x],KeyValuePattern[y_->Nothing]]
Protect[Association]

This works as <|a->1,b->Nothing|> results in <|a->1|>. Be aware that this potentially introduces overhead for Association or might even break functionality based on Association.

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