2

I have a nested list that looks like this:

[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

I want to duplicate each element in each inner list by 3 and place them side to side as such:

[[1, 1, 1, 2, 2, 2, 3, 3, 3], [4, 4, 4, 5, 5, 5, 6, 6, 6], [7, 7, 7, 8, 8, 8, 9, 9, 9]]

This is my current solution:

from itertools import repeat

x2 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

ls = []
for i in x2:
    ls.append([x for item in i for x in repeat(item, 3)])
ls
>>> [[1, 1, 1, 2, 2, 2, 3, 3, 3],
 [5, 5, 5, 6, 6, 6, 7, 7, 7],
 [9, 9, 9, 10, 10, 10, 11, 11, 11],
 [4, 4, 4, 8, 8, 8, 3, 3, 3]]

Is there any way to make it faster?

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
  • If you make use of lambda x function, there is a way to do it using np.repeat()! First use 'f = lambda x:np.repeat(x2,3)'. Then use 'np.apply_along_axis(f,1,x)' and you will get the same answer. – longlichang Dec 10 '20 at 12:10
  • If your code doesn't have any problems and you are looking for improvements; Code Review is the right place to ask not Stack Overflow. – Asocia Dec 10 '20 at 12:10
  • Oh ok sorry this is my first time submitting a question, thank you for your input, I will do so next time. – longlichang Dec 10 '20 at 12:13
  • Thanks, seems to work too :) – longlichang Dec 10 '20 at 12:21
  • 1
    This can be done with a one-liner, list-comprehension `dupes = [[val for val in sublist for i in range(3)] for sublist in x2]`. Not sure if it's faster though. – Wololo Dec 10 '20 at 12:21

2 Answers2

2

Here is one solution:

ls=[sum([[i]*3 for i in k], []) for k in x2]

>>>print(ls)
[[1, 1, 1, 2, 2, 2, 3, 3, 3], [4, 4, 4, 5, 5, 5, 6, 6, 6], [7, 7, 7, 8, 8, 8, 9, 9, 9]]
IoaTzimas
  • 10,538
  • 2
  • 13
  • 30
1

As you asked for faster, here are some comparisons between the different possible ways presented here and other places.

The results (on my machine) are (ordered ascending):

using_zip         5.630
using_repeat_comp 5.818
using_sum         5.905
using_repeat      6.421
using_pure        6.878

Surprisingly (to me), the zip solution is actually fastest, and the list-comp version of your repeat solution second. I would assume that the "pure" list-comp will be fastest but it was actually the worst. I guess TIL...


There is another result (proposed by @Henry Tjhia):

using_sort        3.219

Significantly better as you can see, but I put it separately as it relies heavily on the above specific example. So if you want to duplicate a list of ascending numbers that would be your best choice.


The code to produce them is:

import timeit
from itertools import repeat

x2 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

def using_repeat():
    ls = []
    for i in x2:
        ls.append([x for item in i for x in repeat(item, 3)])
    return ls

def using_repeat_comp():
    return [[x for item in i for x in repeat(item, 3)] for i in x2]

def using_zip():
    return [[x for triple in zip(l, l, l) for x in triple] for l in x2]

def using_sum():
    return [sum([[i]*3 for i in k], []) for k in x2]

def using_pure():
    return [[val for val in sublist for _ in range(3)] for sublist in x2]

def using_sort():
    return [sorted(sub[:]*3) for sub in x2]

for func in [using_repeat, using_repeat_comp, using_zip, using_sum, using_pure, using_sort]:
    print(func.__name__, timeit.timeit(f"{func.__name__}()", f"from __main__ import {func.__name__}"))
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
  • 1
    Ah, you beat me to it: I was just finishing my `timeit` testing of the same approaches, +1!. It intrigues me that `zip` is fastest.. it is also the "least" expandable approach, say if the user suddenly wants 4 copies and not 3.. – Wololo Dec 10 '20 at 13:06
  • 1
    @Wololo agree. It surprised me as well. My natural choice would be your list-comp which surprisingly as well is actually the slowest! – Tomerikoo Dec 10 '20 at 13:07
  • My bad, I just noticed that. In my testing with your code, the ```sum``` way always consistently outperforms the ```zip``` and others. – Henry Tjhia Dec 10 '20 at 13:48
  • @Tomerikoo That would be great. But since ordering is important, we can forget it :). – Henry Tjhia Dec 10 '20 at 13:57
  • 1
    @HenryTjhia, no don't forget it. When it comes to optimization, specific problems may often need specific solutions, and a performance boost like that is not to be trifled with. This was an eye-opener for me, and a valuable lesson. – Wololo Dec 10 '20 at 14:00