I thought Riffle
would generalize such that
Riffle[{a,b,c},{1,2,3},{x,y,z}]
would return
{a,1,x,b,2,y,c,3,z}
It turns out that's not the case.
What's the easiest way to do a multi-list riffle?
{{a, b, c}, {1, 2, 3}, {x, y, z}} ~Flatten~ {2, 1}
{a, 1, x, b, 2, y, c, 3, z}
Flatten
had this more sophisticated use. Plus, this one properly flattens levels.
$\endgroup$
Commented
Sep 5, 2014 at 15:16
Join @@ Transpose @ lists
in most cases. (You still have my vote, Simon.)
$\endgroup$
Commented
Sep 5, 2014 at 15:25
Riffle
does more than simply interleave lists of equal length. When the lists are not of the same length it will repeat elements from the second list, and it will also leave an element from the first list last position:
Riffle[{a, b, c, d, e, f}, {1, 2, 3}]
{a, 1, b, 2, c, 3, d, 1, e, 2, f}
How this would be generalized to multiple lists is not clear which I suspect is why Riffle
permits only two lists as input.
Perhaps you would find use, or at least interest, in the following construct:
multiRiffle[x : _List ..] :=
Module[{i = 1},
Fold[Riffle[##, {++i, -1, i}] &, {x}]
]
Now:
multiRiffle[{a, b, c}, {1, 2, 3}, {x, y, z}]
{a, 1, x, b, 2, y, c, 3, z}
But also:
multiRiffle[{a, b, c, d}, {1, 2}, {x, y, z}]
{a, 1, x, b, 2, y, c, 1, z, d, 2, x}
multiRiffle[{a, b}, {1, 2, 3, 4}, {x}]
{a, 1, x, b, 2, x}
I think these are closer in spirit to Riffle
than a simple transpose/flatten operation.
Riffle
's generalization. Indeed in my application I assume equal-length lists and so @SimonWoods' solution works; however I appreciate the insight into an actually generalized Riffle
.
$\endgroup$
Commented
Sep 5, 2014 at 15:20
Flatten @ Transpose[{{a, b, c}, {1, 2, 3}, {x, y, z}}]
{a, 1, x, b, 2, y, c, 3, z}
Flatten[Transpose[{{a, b, c}, {1, 2, 3}, {x, y, z}}], 1]
if your elements are lists themselves, or else they'll be flattened too.
$\endgroup$
Commented
Sep 5, 2014 at 15:15
Join @@
$\endgroup$
Commented
Sep 5, 2014 at 15:18
Two people asked me to re-post a comment as a separate answer for greater visibility.
Regarding Simon's Flatten
method I commented:
Worth noting is that despite being a single clean operation this is actually slower than
Join @@ Transpose @ lists
in most cases.
Part of the reason that I "only" commented is that I had not invested the time necessary to back up this claim, and as we will see it is questionable. Here are the two functions I shall be comparing and the test
function I shall use:
f1 = # ~Flatten~ {2, 1} &;
f2 = Join @@ (#\[Transpose]) &;
test = Table[First @ RepeatedTiming @ fn[#], {fn, {f1, f2}}] &;
All timings are being performed in version 10.1.0 under Windows x64.
First with packed integers with three different array shapes:
RandomInteger[99, {50000, 5}] // test
RandomInteger[99, {5, 50000}] // test
RandomInteger[99, {500, 500}] // test
{0.00200, 0.00115} {0.00209, 0.0127} {0.00205, 0.00164}
So f1
(Flatten
) is uniform in speed whereas f2
varies with the shape of the array. In the case where input is only a few very long rows its is significantly slower than f1
, but in the other two cases it does pull ahead.
With unpackable data:
RandomChoice[{"a", "b", "c"}, {50000, 5}] // test
RandomChoice[{"a", "b", "c"}, {5, 50000}] // test
RandomChoice[{"a", "b", "c"}, {500, 500}] // test
{0.00788, 0.00558} {0.00626, 0.00774} {0.00684, 0.00359}
both functions slow down with the exception of f2
on the long-rows case where it is actually faster (but still slower than f1
on the same data). Timings are fairly similar in the first two cases but with the square matrix f2
is nearly twice as fast.
I conclude that my statement that f2
is faster "in most cases" is dubitable, however f2
is enough faster in some cases that it is still worth knowing.
More genaral approach:
Flatten@Riffle[{a, b, c, d, e, f, g}, Transpose@{{1, 2, 3}, {x, y, z}}]
(*{a, 1, x, b, 2, y, c, 3, z, d, 1, x, e, 2, y, f, 3, z, g}*)
MapThread[Sequence, {{a, b, c}, {1, 2, 3}, {x, y, z}}]
{a, 1, x, b, 2, y, c, 3, z}
Thread[Unevaluated @ Sequence[{a, b, c}, {1, 2, 3}, {x, y, z}]]
{a, 1, x, b, 2, y, c, 3, z}