4
$\begingroup$

If I have a list of lists $a$ and a list of occurrences of each sublist $n$

a={ {1,1,1}, {2,2,2}, {3,3,3} }
n={1,3,2}

what is the most efficient way to get the following list?

l={{1,1,1},{2,2,2},{2,2,2},{2,2,2},{3,3,3},{3,3,3}}

My current implementation is

l=Flatten[Table[Table[a[[i]],{x,n[[i]]}],{i,Range[Length[n]]}],1]

EDIT

Thank you for the answers!

For the problem as posted, the fastest solution is Catenate[...] from march (inspired by J.M.) at 1.7 10^-5 seconds (AbsoluteTiming), with all other solutions being above 2 10^-5.

If I drastically increase the number of samples I want (for example multiplying n*100), then Catenate[MapThread[Table, {a, List /@ n}]]; takes 1.5 10^-3 seconds and the fastest solution by far is a[[Join @@ MapIndexed[ConstantArray[#2[[1]], #1] &, n]]]; from ubpdqn, at 7.7 10^-5.

In both cases, solutions from garej had intermediate timings.

So I guess the ideal solution depends on the exact problem (size of the array, number of samples, ...) and may or may not have a great impact on the overall performance.

$\endgroup$
  • 6
    $\begingroup$ Flatten[MapThread[ConstantArray, {a, n}], 1]? $\endgroup$ – J. M. is away Apr 4 '16 at 15:01
  • $\begingroup$ @Delphine If you're using Mma 10, I think Catenate will be about 20% faster than Flatten[..., 1]. $\endgroup$ – Martin Ender Apr 4 '16 at 15:18
6
$\begingroup$
a[[Join @@ MapIndexed[ConstantArray[#2[[1]], #1] &, n]]]
$\endgroup$
  • $\begingroup$ Your solution is actually the fastest. Can you explain a bit what it does? $\endgroup$ – Delphine Apr 5 '16 at 9:54
  • $\begingroup$ @Delphine MapIndexed uses the index as position in list.ConstantArray just produces the desired number of the position. Join just makes a flat list and then you just use Part ([[...]]) to select the desired outcome. @MartinButtner notes Catenate is faster. This could also be used. $\endgroup$ – ubpdqn Apr 5 '16 at 10:26
  • $\begingroup$ @ubpdqn, If possible please tell why did not you use of Flatten instead of Join? is there any special reason? $\endgroup$ – Unbelievable Jun 2 '16 at 19:28
  • $\begingroup$ @Irreversible No special reason. Could use Join. $\endgroup$ – ubpdqn Jun 2 '16 at 22:35
5
$\begingroup$
Table @@@ Transpose[{a, n}] // Catenate

{{1, 1, 1}, {2, 2, 2}, {2, 2, 2}, {2, 2, 2}, {3, 3, 3}, {3, 3, 3}}

Edit Also

Join @@ Table @@@ Thread[{a, n}]
$\endgroup$
  • $\begingroup$ These are good solutions too, very elegant, but not the fastest. $\endgroup$ – Delphine Apr 5 '16 at 10:10
3
$\begingroup$

From a comment by J.M., what I consider to be the most natural solution:

Flatten[MapThread[ConstantArray, {a, n}], 1];

Via Martin, alternatively do

MapThread[ConstantArray, {a, n}] // Catenate;

You can also do something similar using pure functions and Apply:

ConstantArray[#1, #2] & @@@ Thread[{a, n}] // Catenate;

This is just about as fast as the previous version. You can also get around having to Catenate at the end by using Sequence all along the way, i.e.

Sequence @@ ConstantArray[#1, #2] & @@@ Thread[{a, n}];

but it turns out that this is a little slower (maybe 25% slower).

I tried to come up with a ReplaceAll version, but they were all ten times slower.

The fastest so far seems to be again by J.M. Pre 10.2 version is

Catenate[MapThread[Table, {a, List /@ n}]];

and 10.2 and later is

Catenate[MapThread[Table, {a, n}]];
$\endgroup$
  • 2
    $\begingroup$ Apparently Table[] also works: Catenate[MapThread[Table, {a, n}]] $\endgroup$ – J. M. is away Apr 4 '16 at 17:37
  • 1
    $\begingroup$ @J.M. Perhaps in version newer than V10.0. I had to do Catenate[MapThread[Table, {a, List /@ n}]] to make that work, but it turned out to be 4 times faster than the others! $\endgroup$ – march Apr 4 '16 at 17:44
  • $\begingroup$ yes, that's the classical syntax for Table[]: Table[1, {5}]. Thus my surprise when I forgot to put in the list for the iterator and it worked anyway. $\endgroup$ – J. M. is away Apr 4 '16 at 17:46
  • $\begingroup$ I varied the size of the array a and the number of replicates n. It appears this last solution is the fastest, but only if the arrays or the number of replicates are small. $\endgroup$ – Delphine Apr 5 '16 at 10:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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