3
$\begingroup$

I have a list,

{a,b,c,d,...,z}

And I want to duplicate that list n times such that,

{a,a,a,b,b,b,c,c,c,....z,z,z}.

I have found the Table function can create duplicates by appending to the end of the list. Is this the way to go and then reordering? If so, how?

Any help would be appreciated.

$\endgroup$
0

4 Answers 4

7
$\begingroup$

You can use Map (or its shorthand /@) together with Sequence over the list:

list = {a, b, c}
Sequence[#, #, #] & /@ list
(* {a, a, a, b, b, b, c, c, c} *)

For larger amounts of repetition, that gets annoying. In that case, you can use ConstantArray and the remove the List head:

list = {a, b, c}
n = 5
Sequence @@ ConstantArray[#, n] & /@ list
(* {a, a, a, a, a, b, b, b, b, b, c, c, c, c, c} *)

As J. M. mentions you can also use Flatten (or even Join) instead of Sequence:

Flatten[ConstantArray[#, n] & /@ list]
Join @@ (ConstantArray[#, n] &) /@ list
$\endgroup$
2
  • 1
    $\begingroup$ I'd have used Flatten[] myself. $\endgroup$ Apr 22, 2016 at 15:14
  • $\begingroup$ @J.M. Hm yeah I considered that, but it seems more natural to me to just "expand" each element in its place in the list instead of turning it into 2D first and then flattening it back down to 1 level again, but I've added it for completeness. Thanks. :) $\endgroup$ Apr 22, 2016 at 15:16
8
$\begingroup$
f1 = Flatten@Transpose@ConstantArray@## &;
f2 = With[{ls = #}, Flatten[Transpose@Array[ls &, #2]]] &;
f3 = Flatten@Transpose[Table[#, {#2}]] &;
f4 = Flatten[ArrayPad[List /@ #, {{0, 0}, {0, #2 - 1}}, "Fixed"]] &;

lst = {a, b, c, d};

f1[lst, 3]

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

 Equal @@ (#[lst, 3] & /@ {f1, f2, f3, f4})

True

Timings:

list = RandomReal[{0, 1}, 1000000];
n = 3;
{t1, r1} = f1[list, n] // AbsoluteTiming;
{t2, r2} = f2[list, n] // AbsoluteTiming;
{t3, r3} = f3[list, n] // AbsoluteTiming;
{t4, r4} = f4[list, n] // AbsoluteTiming;
{t5, r5} = Flatten[ConstantArray[#, n] & /@ list] // AbsoluteTiming;
{t6, r6} = Sequence @@ ConstantArray[#, n] & /@ list // AbsoluteTiming;
{t7, r7} = Flatten@Replace[list, a_ :> Table[a, {n}], 1] // AbsoluteTiming;
{t8, r8} = Flatten[NestList[# &, #, 2] & /@ list] // AbsoluteTiming;

{t1, t2, t3, t4, t5, t6, t7, t8}

{0.044306, 0.034579, 0.021672, 0.111301, 0.558783, 2.088776, 1.020894, 0.369900}

Equal @@ {r1, r2, r3, r4, r5, r6, r7, r8}

True

$\endgroup$
2
  • $\begingroup$ Maybe you want to add a benchmark for all methods? then I would delete my answer. $\endgroup$
    – BlacKow
    Apr 22, 2016 at 15:43
  • $\begingroup$ @BlacKow, i will add timings in a moment. $\endgroup$
    – kglr
    Apr 22, 2016 at 16:10
3
$\begingroup$

This one is just for fun,

list = ToExpression /@ Alphabet[]
Most@Fold[Riffle[#1, list, #2] &, list~Join~{dummy}, Range[2, 5]]

(* {a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, 
u, v, w, x, y, z} *)

(* {a, a, a, a, a, b, b, b, b, b, c, c, c, c, c, d, d, d, d, d, 
e, e, e, e, e, f, f, f, f, f, g, g, g, g, g, h, h, h, h, h, i, i, i, 
i, i, j, j, j, j, j, k, k, k, k, k, l, l, l, l, l, m, m, m, m, m, n, 
n, n, n, n, o, o, o, o, o, p, p, p, p, p, q, q, q, q, q, r, r, r, r, 
r, s, s, s, s, s, t, t, t, t, t, u, u, u, u, u, v, v, v, v, v, w, w, 
w, w, w, x, x, x, x, x, y, y, y, y, y, z, z, z, z, z} *)

You need the dummy variable or else Riffle won't put any extra zs on the end.

$\endgroup$
1
$\begingroup$

A replacement version:

lst = {a, b, c, d};
Replace[lst, a_ :> Sequence[a, a, a], 1]
(* {a, a, a, b, b, b, c, c, c, d, d, d} *)

or

Replace[lst, a_ :> Sequence @@ Table[a, {5}], 1]
(* {a, a, a, a, a, b, b, b, b, b, c, c, c, c, c, d, d, d, d, d} *)

or, slightly faster,

Flatten@Replace[lst, a_ :> Table[a, {5}], 1]
$\endgroup$
1
  • 2
    $\begingroup$ Another alternative: Cases[lst, x_ :> Sequence[x, x, x, x]] $\endgroup$
    – user1066
    Apr 22, 2016 at 19:03

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