# What is the fastest way of combining elements of lists in rules?

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.

• 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 Dec 8 '17 at 13:48
• Turns out the fastest one is using AssociationThread, at least in my code (which has way longer lists). Dec 12 '17 at 14:52

One straightforward way is with AssociationThread.

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

(* {<|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}}

(* {<|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]},
]


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}}

• 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. Dec 7 '17 at 11:04
• @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 Dec 7 '17 at 11:21
• @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. Dec 7 '17 at 11:31
• @Coolwater Good point. I tend to project everything I see to larger list... However, the OP's question was also about performance. Dec 7 '17 at 11:49
• @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. Dec 7 '17 at 11:52
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}}


Use Outer:

lst01 = {{a, b}, {c, d}}
lst02 = {{e, f}, {g, h}}

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).