1
$\begingroup$

I would like to use JoinAcross to combine several lists of associations. Extending an example from the documentation, I'd like to do this:

JoinAcrossList[{{<|a -> 1, b -> X|>}, {<|a -> 1, c -> Y|>}, {<|a -> 1,
 e -> Z|>}}, Key[a]]

Of course, this fails. I have a way of doing this but am wondering if there is anything built-in that would do it or perhaps a more efficient way.

My solution is to use this:

JoinAcrossList[{{<|a -> 1, b -> X|>}, {<|a -> 1, c -> Y|>}, {<|a -> 1, e -> Z|>}}, Key[a]]

Where

JoinAcrossList[associations_List, joinKey_] := Fold[JoinAcross[#1, #2, joinKey] &, associations[[1]], Drop[associations, 1]];

The above example gives this:

In[]:= JoinAcrossList[{{<|a -> 1, b -> X|>}, {<|a -> 1, 
c -> Y|>}, {<|a -> 1, e -> Z|>}}, Key[a]]

Out[]= {<|a -> 1, b -> X, c -> Y, e -> Z|>}

Which is the desired result. It also works for the case where the list contains only two elements such as this example:

JoinAcrossList[{{<|a -> 1, b -> X|>}, {<|a -> 1, c -> Y|>}}, Key[a]]

As I write this, I realize that a more efficient combination would probably split this into multiple pairs and then perform successive combinations of those. Would be nice to have a built-in function for this if the number of elements in the list is large.

I can see how to divide a list of elements into pairs using something like the following but not yet sure how to evaluate starting at the lowest elements and then building back up.

NestWhile[Partition[#, 2, 2, {1, 1}, {}] &, Range[11],Ceiling[Length[#]/2] != 1 &]
$\endgroup$
4
  • 2
    $\begingroup$ What exactly is your question? How to do an efficient implementation of the function JoinAcrossList? $\endgroup$ Jun 2, 2019 at 3:54
  • $\begingroup$ Yes, I'm wondering if there is a more efficient way to do this with some built in operators. What I have works. $\endgroup$
    – Mark R
    Jun 2, 2019 at 7:21
  • 1
    $\begingroup$ Just as a small tip: Fold[f, list] is equivalent to Fold[f, First[list], Rest[list]]. $\endgroup$ Jun 2, 2019 at 9:20
  • $\begingroup$ Thanks for the tip! $\endgroup$
    – Mark R
    Jun 2, 2019 at 17:57

1 Answer 1

1
$\begingroup$
JoinAcrossList1[list_, key_] := Fold[JoinAcross[#1, #2, key] &, list][[1]]

JoinAcrossList1[{{<|a -> 1, b -> X|>}, {<|a -> 1, c -> Y|>}, {<|a -> 1, e -> Z|>}}, Key[a]]

<|a -> 1, b -> X, c -> Y, e -> Z|>

This uses binary subdivision and recursion, but I doubt that it will be faster.

ClearAll[f];
f[list_, key_] /; Length[list] == 1 := list;
f[list_, key_] /; Length[list] == 2 := {JoinAcross[list[[1]], list[[2]], key]};
f[list_, key_] := f[
  Join[
   f[list[[;; Quotient[Length[list], 2]]], key],
   f[list[[Quotient[Length[list], 2] + 1 ;;]], key]
   ],
  key
  ]
JoinAcrossList2[list_, key_] := f[list, key][[1, 1]]
$\endgroup$
2
  • $\begingroup$ I like what you wrote but as you suspected, it isn't actually faster. Will post some timings. $\endgroup$
    – Mark R
    Jun 2, 2019 at 7:28
  • $\begingroup$ For 3 elements to the list: 0.00007 for JoinAcrossList2 and 0.000049 for JoinAcrossList. For 4 elements, where I would think that the split might help, 0.000091 for JoinAcrossList2 and 0.000064 for JoinAcrossList. $\endgroup$
    – Mark R
    Jun 2, 2019 at 7:35

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.