Data re-structuring by Thread

Thread can do this

Thread[{a, {b, c, d}}]

{{a, b}, {a, c}, {a, d}}


But when above a, b, c and d are themselves Lists, for instance, used as a representation for 2D/3D points, it will not work as a naive generalization

Thread[{{a, b}, {{x, y}, {z, w}, {u, v}}}]


which just raises an error.

Here what is intended for is

{{{a, b}, {x, y}}, {{a, b}, {z, w}}, {{a, b}, {u, v}}}


So can it still be realized by Thread? If yes, how? If no, then do there exist any concise and efficient workarounds?

A level specification can help (we have to specify the head to thread over, too):

Thread[{{a, b}, {{x, y}, {z, w}, {u, v}}}, List, {2}]


{{{a, b}, {x, y}}, {{a, b}, {z, w}}, {{a, b}, {u, v}}}

Note that this unpacks arrays, so I would not suggest that for big datasets. I that case, I would propose a ConstantArray/Transpose combo:

n = 1000000 ;
a = RandomReal[{-1, 1}, 2];
b = RandomReal[{-1, 1}, {n, 2}];

Thread[{a, b}, List, {2}] // DeveloperPackedArrayQ // AbsoluteTiming

Transpose[{ConstantArray[a, n],b}] // DeveloperPackedArrayQ // AbsoluteTiming


{0.347755, False}

{0.046035, True}

• It seems it. So any clarification for the curly brackets around 2 here? The F1 documentation of Thread does not mention level specification. – Αλέξανδρος Ζεγγ Sep 17 '18 at 4:19
• For level specifications, f[...,n] with integer n usually means "until level n" while f[...,{n}] means "only at level n". – Henrik Schumacher Sep 17 '18 at 4:21
• Sorry, do you mean f[..., {n}] in the latter? – Αλέξανδρος Ζεγγ Sep 17 '18 at 4:23
• Yes. But I fixed the comment already. Thanks for the accept btw. – Henrik Schumacher Sep 17 '18 at 4:51
• Your information on packed array is valuable. – Αλέξανδρος Ζεγγ Sep 17 '18 at 5:54