4
$\begingroup$

I'd like to a create a list from A = {{a}, {b}, {c}} by taking each elements n times in the following form:

B={{a},{a},{a},{b},{b},{b},{c},{c},{c}}

Any idea?

$\endgroup$
0

7 Answers 7

5
$\begingroup$

ConstantArray is your friend.

Flatten[ConstantArray[#, 3] & /@ {{a}, {b}, {c}}, 1]
{{a}, {a}, {a}, {b}, {b}, {b}, {c}, {c}, {c}}
$\endgroup$
4
$\begingroup$

Here is an interesting approach:

We first define a helper function:

f[x_] := Sequence[x, x, x]

Then it's just a matter of mapping it on A to create B:

A = {{a}, {b}, {c}}; 

f /@ A    

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

We could also use a SubValues (or "operator form") definition for flexible replication:

g[n_][x_] := Sequence @@ ConstantArray[x, n];

g[3] /@ A

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

MapAt[g[3], A, 2]

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

$\endgroup$
4
  • $\begingroup$ Nice idea. I added an extension assuming you wouldn't mind. $\endgroup$
    – Mr.Wizard
    Aug 7, 2014 at 18:15
  • $\begingroup$ @Mr.Wizard. I don't mind your edits at all. Nice addition by the way. Thanks. $\endgroup$
    – RunnyKine
    Aug 7, 2014 at 18:17
  • $\begingroup$ Unfortunately this method proves to be one of the slower ones. See my updated answer. (The colors are hard to distinguish but f9 is the line third from the top, meaning third slowest.) $\endgroup$
    – Mr.Wizard
    Aug 7, 2014 at 18:52
  • $\begingroup$ @Mr.Wizard. Oh well, we can't win all the time :) $\endgroup$
    – RunnyKine
    Aug 7, 2014 at 18:54
4
$\begingroup$

My additions, duplicating the entire array first:

ConstantArray[A, 3] ~Flatten~ {2, 1}

Join @@ (ConstantArray[A, 3]\[Transpose])

Join @@ Thread @ ConstantArray[A, 3]

Sequence ~MapThread~ ConstantArray[A, 3]

Benchmarks

Timings for all methods in the order they were posted, tested only for triplication on a packed array.

f1[array_] := 
 Composition[Flatten[#, 1] &, Replace[#, x_ :> ConstantArray[x, 3], 1] &][array]
f2[A_] := Flatten[ConstantArray[#, 3] & /@ A, 1]
f3[A_] := Flatten[A /. {x_} :> {{x}, {x}, {x}}, 1]
f4[A_] := Flatten[{#, #, #} & /@ A, 1]
f5[A_] := ConstantArray[A, 3] ~Flatten~ {2, 1}
f6[A_] := Join @@ (ConstantArray[A, 3]\[Transpose])
f7[A_] := Join @@ Thread @ ConstantArray[A, 3]
f8[A_] := Sequence ~MapThread~ ConstantArray[A, 3]
f[x_] := Sequence[x, x, x];
f9[A_] := f /@ A

gen = RandomInteger[99, {#, 1}] &;

Needs["GeneralUtilities`"]

BenchmarkPlot[
  {f1, f2, f3, f4, f5, f6, f7, f8, f9},
  gen, 2^Range[20], "IncludeFits" -> True
]

enter image description here

All methods have the same order of complexity but there is a clear winner for speed:

f5[A_] := ConstantArray[A, 3] ~Flatten~ {2, 1}

Running the tests again with unpackable data:

gen2 = "a" ~CharacterRange~ "z" ~RandomChoice~ {#, 1} &;

BenchmarkPlot[
  {f1, f2, f3, f4, f5, f6, f7, f8, f9},
  gen2, 2^Range[20], "IncludeFits" -> True
]

enter image description here

The winners are f6, f7, and f5 in order, with f6 and f7 only slightly ahead of f5 which does not justify their use given f5's large margin of performance on packed data.

$\endgroup$
4
  • $\begingroup$ +1 for Flatten. BTW my MMA 10 could not generate BenchmarkPlot. All I got was this. $\endgroup$
    – seismatica
    Aug 7, 2014 at 19:20
  • $\begingroup$ @seismatica Thanks for the vote. Very strange error; I guess BenchmarkPlot has some bugs to work out. The package is very new and rough in spots. $\endgroup$
    – Mr.Wizard
    Aug 7, 2014 at 19:32
  • $\begingroup$ Is this a built-in package or do I have to download it somewhere? $\endgroup$
    – seismatica
    Aug 7, 2014 at 19:32
  • $\begingroup$ @seismatica It is built into version 10 and should be loaded by the line Needs["GeneralUtilities`"] $\endgroup$
    – Mr.Wizard
    Aug 7, 2014 at 19:39
2
$\begingroup$

Just for variation, using replacement rules we have for small n:

Flatten[{{a}, {b}, {c}} /. {x_} :> {{x},{x},{x}}, 1]

and for large n :

Flatten[{{a}, {b}, {c}} /. {x_} :> Table[{x}, {3}], 1]
$\endgroup$
1
  • 1
    $\begingroup$ For large n, Table will slow down a bit. $\endgroup$
    – rcollyer
    Aug 7, 2014 at 13:43
1
$\begingroup$

Use Replace with levelspec = 1

createArray[array_, n_] := Composition[
   Flatten[#, 1] &,
   Replace[#, x_ :> ConstantArray[x, n], 1] &
   ][array]

Check function:

createArray[{{a},{b},{c}}, 3]
(*{{a},{a},{a},{b},{b},{b},{c},{c},{c}}*)
$\endgroup$
1
$\begingroup$

Different approaches (just for fun)

Join @@ (ComposeList[Table[# &, {2}], #] & /@ A)
Join @@ (Nest[Append[#, First@#] &, {#}, 2] & /@ A)
Join @@ (NestList[# &, #, 2] & /@ A)
Fold[Riffle[#1, A, {#2, -1, #2}] &, A, {2, 3}]
Join @@ MapThread[List, Table[A, {3}]]
$\endgroup$
0
$\begingroup$
Flatten[PadLeft[{#}, 3, {#}] & /@ {{a}, {b}, {c}}, 1]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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