How to thread a list

Another approach using Transpose:

Transpose[{Table[First@#,{Length@#-1}],Rest@#},{3,1,2}]&@data
(* Out[1]= {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} *)

On my pc, it is about 3 times faster than the Outer/Flatten approach.

edit:

It seems that the bottleneck is Table.By changing it into ConstantArray:

Transpose[{ConstantArray[First@#,Length@#-1],Rest@#},{3,1,2}]&@data

Now it is about 10 times faster than the Outer/Flatten approach.


If your lists are long, there are faster approaches using high-level functions and structural operations. Here are two alternatives.

First we try Outer and Flatten:

data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}};
Flatten[Outer[List, List@First[data], Rest[data], 1], {{2}, {1, 4}}]
{{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}}

And now Distribute and Transpose:

Transpose[Distribute[{List@First[data], Rest[data]}, List], {1, 3, 2}]
{{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}}

Evidently, they give the correct result. Now for a Timing comparison:

data = RandomReal[{0, 1}, {10^6, 2}];

The timings, in rank order, are:

  1. kptnw's Table/Transpose method: 0.297 seconds
  2. Outer/Flatten: 0.812 seconds
  3. Distribute/Transpose: 0.891 seconds
  4. rcollyer's Thread/Map approach: 2.907 seconds
  5. R.M's Transpose/FoldList method: 3.844 seconds
  6. paradox2's solution with Riffle and Partition: 7.407 seconds

The Outer/Flatten and Distribute/Transpose approaches are quite fast, but clearly Table is much better-optimized than Distribute, since while these two methods are conceptually similar, kptnw's solution using the former is by far the fastest and most memory-efficient. The other solutions, not using structural operations, are considerably slower, which is not unexpected.


This works:

data = {{a1,a2}, {b1, b2}, {c1, c2}, {d1, d2}}
With[{fst = First@#, rst = Rest@#}, Thread[{fst, #}] & /@ rst]& @ data
{{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}}