Home > OS >  Efficient way to sequential adding multiple list elements
Efficient way to sequential adding multiple list elements

Time:10-17

I have multiple lists. I want to merge the elements sequentially one-by-one.

Example:

a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]

Result should be:

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

One way of doing it is:

d = []
for i, j, k in zip(a, b, c):
    d.extend([i, j, k])

Is this efficient? What is most efficient way here?

CodePudding user response:

A one-liner could be

import itertools
list(itertools.chain.from_iterable(zip(a,b,c)))

A variant of your method is

d=[]
for i, j, k in zip(a, b, c):
    d =[i,j,k]

Out of curiosity, i've just Just used timeit, out of curiosity, comparing your method, that variant, my one-liner, and also the one in Olvin's comment (let's call it compound version), and verdict is

  • yours: 1.06-1.08
  • my variant (with = instead of extend): 0.94-0.97
  • my one-liner: 1.10-1.12
  • Olvin's one-liner: 1.28-1.34

Sometimes, the nicest methods aren't the fastest. Timing may change for longer lists tho.

The fact that = is faster than .extend is quite interesting (since .extend change the list, while = build a new one, and then replace the old one. Instinct would say that rebuilding lists should be faster that extending them. But maybe memory management says otherwise).

But, well, so far, the fastest one is my second version (with =), which, incidentally, is also the one I find the most boring, among all solutions seen here.

Edit

Since that ranking bothered me (it's itertools iterators are supposed to be faster, since they are a little bit less interpreted and a little bit more compiled), I've tried with longer list. And it is then another story

a=list(range(1000))
b=list(range(1000,2000))
c=list(range(2000,3000))

And then timeit verdict (with 100 times less run than before) is

  • Your method: 1.91
  • My = variant: 1.59
  • My one-liner: 0.98
  • Olvin's one-liner: 1.88

So, at least, itertools does win in the long run (with big enough data).

Victory of = over .extend is affirmed (I don't really know the internals of memory management. But, coming from the C world, I would say that sometimes, a new malloc and copy is faster than a constantly realloc. But maybe that's a naive view of what happens under the hood in python's interpreter. But well, is faster than extend for this usage in the long run)

Olvin's method is quite equivalent to yours. Which surprises me a little. Because it is roughly the compound version of the same thing. But I would have thought that, while building up a compound list, python could skip some steps in intermediary representation, that it could not skip in your method, where all the versions of the list (the one with just [1,4,7], then the one with [1,4,7,2,5,8] etc.) do exist in the interpreter. May be the 0.03 difference between Olvin's method and yours are because of that (it is not just noise. With this size, the timings are quite constant, and the 0.03 difference is also). But I would have thought that the difference would be higher.

But well, even if the timing differences surprise me, the ranking of the method makes more sense with big lists. With itertools > = > .extend > [compound]

CodePudding user response:

a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]

flat = zip(a,b,c)

d = [x for tpl in flat for x in tpl]

This list comprehension is the same as:

flat_list = []
for sublist in l:
    for item in sublist:
        flat_list.append(item)
  • Related