5
$\begingroup$

Let us take the following two toy lists:

{{a,b},{c,d}} and {{e,f},{g,h}}

And let's say that I want to combine them such that I get the following:

{{a -> e, b -> f}, {a -> g, b -> h}, {c -> e, d -> f}, {c -> g, d -> h}}

This can obviously be done with Table, MapThread and who knows how many ways. The question is, what is the fastest way in terms of computational time?

EDIT

The lists need not to be of the same dimensions. Fore example, one could have:

{a,b} and {{c,d},{e,f}}

to get {{a -> c, b -> d}, {a -> e, b -> f}}.

Only the last levels of the lists need to have the same number of elements in order to combine them into Rules.

$\endgroup$
2
  • $\begingroup$ I'll test the answers on my actual dataset and get back to you to see what is the response of AbsoluteTiming for each of your solutions. Best performance gets accepted answer, obivously. Stay tuned :D $\endgroup$
    – user50473
    Dec 8, 2017 at 13:48
  • $\begingroup$ Turns out the fastest one is using AssociationThread, at least in my code (which has way longer lists). $\endgroup$
    – user50473
    Dec 12, 2017 at 14:52

3 Answers 3

3
$\begingroup$

One straightforward way is with AssociationThread.

keys = {{a, b}, {c, d}}
values = {{e, f}, {g, h}}

AssociationThread @@@ Tuples[{keys, values}]

(* {<|a -> e, b -> f|>, <|a -> g, b -> h|>, 
    <|c -> e, d -> f|>, <|c -> g, d -> h|>} *)

And for the second example:

keys = {{a, b}}
values = {{e, f}, {g, h}}

AssociationThread @@@ Tuples[{keys, values}]

(* {<|a -> d|>, <|a -> f|>, <|b -> d|>, <|b -> f|>} *)

Of course, you end up with a list of Associations, but is that such a bad thing? You can always turn it into a list with Normal.

As for the second example, it clearly doesn't meet your "lists need not be of the same dimensions" specification. You can either take the one liner and use it on keys = {{a, b}} instead of {a, b}, or you can use this longer function, but get the functionality you're after:

listtorules[list1_, values_] := 
 Block[{keys = If[Depth[list1] == 2, {list1}, list1]},
  Normal[AssociationThread @@@ Tuples[{keys, values}]]
  ]

Then

listtorules[{a, b}, {{c, d}, {e, f}}]

listtorules[{{a, b}}, {{c, d}, {e, f}}]

both produce

{{a -> c, b -> d}, {a -> e, b -> f}}
$\endgroup$
7
  • $\begingroup$ If you use the rules only for Replace and friends then Normal is actually contraproductive: Associations tend to be even more efficient in replacements than hash tables generated with Dispatch. $\endgroup$ Dec 7, 2017 at 11:04
  • $\begingroup$ @HenrikSchumacher At least in the examples the set of rules have length 2, and for so short replacement rules Dispatch and Association usually makes things slower $\endgroup$
    – Coolwater
    Dec 7, 2017 at 11:21
  • $\begingroup$ @HenrikSchumacher and @Coolwater I have a mild preference for Associations over Rules, just because it's often cleaner and can be faster, depending on what you're using them for. I personally wouldn't Normalize the Association, but I wanted to leave both possibilities open for the OP. $\endgroup$ Dec 7, 2017 at 11:31
  • $\begingroup$ @Coolwater Good point. I tend to project everything I see to larger list... However, the OP's question was also about performance. $\endgroup$ Dec 7, 2017 at 11:49
  • $\begingroup$ @aardvark2012 That was not meant as criticism. I stumbled upon this fact quite unexpectedly (note that Dispatch is actually made for Replace) some time ago. I just thought this could also to be of interest to the OP. $\endgroup$ Dec 7, 2017 at 11:52
6
$\begingroup$
L1 = {{a, b}, {c, d}};
L2 = {{e, f}, {g, h}};

L1r = ArrayReshape[L1, {Times @@ Most[#], Last[#]}] &[Dimensions[L1]];
L2r = ArrayReshape[L2, {Times @@ Most[#], Last[#]}] &[Dimensions[L2]];

new = Transpose[Tuples[{L1r, L2r}], {1, 3, 2}];
new[[All, All, 0]] = Rule;

new
{{a -> e, b -> f}, {a -> g, b -> h}, {c -> e, d -> f}, {c -> g, d -> h}}
$\endgroup$
2
$\begingroup$

Use Outer:

lst01 = {{a, b}, {c, d}}
lst02 = {{e, f}, {g, h}}
Outer[Thread@*Rule, lst01, lst02, 1]

You'll have to use {{a,b}} instead of {a,b} for your second case. And if you really need not have a matrix of results, you can Catenate the results of the above (but of course that has a cost).

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.