5
$\begingroup$

Say I have the following code:

Merge[{<|"a" -> 1, "b" -> 2|>, <|"a" -> 2, "c" -> 3|>}, Identity]

The output is:

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

But what I really want is the following:

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

I know how to do it in "longhand," but I am wondering if there is a terse option in Merge itself that would accomplish the task.

$\endgroup$
  • 3
    $\begingroup$ By longhand, do you just mean using Merge @* KeyUnion? $\endgroup$ – Pillsy Apr 2 '18 at 18:07
  • $\begingroup$ Actually, no. I was mapping the keys of one over the other. But thanks for teaching me about KeyUnion. That seems to solve the problem. (On a separate note, Wolfram Language has so many built-in functions that it is really hard to keep on top of the list.) If you post your comment as an answer, I will accept it. $\endgroup$ – Shredderroy Apr 2 '18 at 18:16
7
$\begingroup$

The most straightforward way to do this is to use KeyUnion, which along with KeyIntersection, allows for useful customization of what Merge should do with missing keys. Its default behavior is pretty much exactly what you were asking for:

Merge[KeyUnion[{<|"a" -> 1, "b" -> 2|>, <|"a" -> 2, "c" -> 3|>}],      
 Identity]    
(* <|"a" -> {1, 2}, "b" -> {2, Missing["KeyAbsent", "b"]}, 
     "c" -> {Missing["KeyAbsent", "c"], 3}|> *)

If you want just the bare symbol Missing as a sentinel value (which I personally avoid, because MissingQ doesn't work for that), you can use the optional second argument:

Merge[KeyUnion[{<|"a" -> 1, "b" -> 2|>, <|"a" -> 2, "c" -> 3|>}, 
  Missing &],
 Identity]
(* <|"a" -> {1, 2}, "b" -> {2, Missing}, "c" -> {Missing, 3}|> *)

EDIT: As Sjord Smith points out in a comment below, you can use Missing[] (with empty brackets) as a minimal sentinel value and MissingQ will still pick it up:

result = Merge[KeyUnion[{<|"a" -> 1, "b" -> 2|>, <|"a" -> 2, "c" -> 3|>}, 
  Missing[] &],
 Identity]
(* <|"a" -> {1, 2}, "b" -> {2, Missing[]}, "c" -> {Missing[], 3}|> *)

Select[result, FreeQ[_?MissingQ]]
(* <|"a" -> {1, 2}|> *)
| improve this answer | |
$\endgroup$
  • 3
    $\begingroup$ I'm just going to point out that MissingQ[Missing] is False, but MissingQ[Missing[]] is True. So if you want a bare-bones missing token, just use Missing[], instead of Missing. $\endgroup$ – Sjoerd Smit Apr 3 '18 at 14:29
2
$\begingroup$

I know this already has an answer, but I'd like to point out that there is a built-in function that already does this for merging associations with Identity:

GeneralUtilities`AssociationTranspose[{<|"a" -> 1, "b" -> 2|>, <|"a" -> 2, "c" -> 3|>}]

<|"a" -> {1, 2}, "b" -> {2, Missing["KeyAbsent", "b"]}, "c" -> {Missing["KeyAbsent", "c"], 3}|>

If you want to apply a merging function other than Identity, simply map it over the result. Moreover, AssociationTranspose is significantly faster than Merge for large datasets, so that's also useful to keep in mind.

| improve this answer | |
$\endgroup$
  • $\begingroup$ Thanks! Very useful to know. $\endgroup$ – Shredderroy Jul 11 at 12:37

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.