Is it possible to avoid unpacking when merging Association?

One can use TracePrint to see how Flatten is being used by Merge:

TracePrint[
    Merge[{assoc,assoc}, Flatten],
    _Flatten,
    TraceAction->Print@*Developer`PackedArrayForm
];

Flatten[{PackedArray[Real,<10>],PackedArray[Real,<10>]}]

Flatten[{PackedArray[Real,<10>],PackedArray[Real,<10>]}]

Flatten[{PackedArray[Real,<10>],PackedArray[Real,<10>]}]

Notice how Merge builds a list of two packed arrays, and then flattens them. This is why the the arrays become unpacked. To workaround this, you can either convert the list of two packed arrays into a packed array first:

Developer`PackedArrayQ /@ Merge[{assoc, assoc}, Flatten @* Developer`ToPackedArray]

<|1 -> True, 2 -> True, 3 -> True|>

Or you can use Join with Apply (as in Henrik's answer, but using slot free syntax):

Developer`PackedArrayQ /@ Merge[{assoc, assoc}, Apply[Join]]

<|1 -> True, 2 -> True, 3 -> True|>


Instead of using Merge, you can also use AssociationTranspose which is often much faster than Merge and doesn't unpack:

m1 = Merge[{assoc, assoc}, Flatten];
m2 = Flatten /@ GeneralUtilities`AssociationTranspose[{assoc, assoc}];
m1 === m2
Developer`PackedArrayQ /@ m1
Developer`PackedArrayQ /@ m2

True

<|1 -> False, 2 -> False, 3 -> False|>

<|1 -> True, 2 -> True, 3 -> True|>

Frankly, AssociationTranspose + Map is pretty much just superior to Merge like 99% of the time.


Join tries to pack whenever it is possible:

Developer`PackedArrayQ /@ Merge[{assoc, assoc}, Join @@ # &]

<|1 -> True, 2 -> True, 3 -> True|>

One might expect that Catenate should also work, but it does not.