Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: faster than list.extend()

13 views
Skip to first unread message

Chris Rebert

unread,
Nov 16, 2009, 5:41:25 PM11/16/09
to Hyunchul Kim, pytho...@python.org
On Mon, Nov 16, 2009 at 2:30 PM, Hyunchul Kim
<hyunchul...@gmail.com> wrote:
> Hi, all.
>
> I want to improve speed of following simple function.
> Any suggestion?
>
> **********
> def triple(inputlist):
>   results = []
>   for x in inputlist:
>     results.extend([x,x,x])
>   return results
> **********

You'd probably be better off calling .append() 3 times instead of
.extend() as it would avoid the creation of all those intermediate
3-element lists.

Cheers,
Chris
--
http://blog.rebertia.com

Tim Chase

unread,
Nov 16, 2009, 5:55:55 PM11/16/09
to Hyunchul Kim, pytho...@python.org
Hyunchul Kim wrote:
> Hi, all.
>
> I want to improve speed of following simple function.
> Any suggestion?
>
> **********
> def triple(inputlist):
> results = []
> for x in inputlist:
> results.extend([x,x,x])
> return results
> **********

Several ways occur to me:

def t1(i):
for x in i:
yield x
yield x
yield x

def t2(i):
r = range(3)
return (x for x in i for _ in r)


I prefer to return generators in case the input is large, but in
both cases, you can just wrap it in list() like

list(t1(inputlist))

or in t2(), you can just change it to use

return [x for x in i for _ in r]

-tkc


Raymond Hettinger

unread,
Nov 16, 2009, 6:28:40 PM11/16/09
to
On Nov 16, 2:41 pm, Chris Rebert <c...@rebertia.com> wrote:
> On Mon, Nov 16, 2009 at 2:30 PM, Hyunchul Kim
>
> <hyunchul.mail...@gmail.com> wrote:
> > Hi, all.
>
> > I want to improve speed of following simple function.
> > Any suggestion?
>
> > **********
> > def triple(inputlist):
> >   results = []
> >   for x in inputlist:
> >     results.extend([x,x,x])
> >   return results


Here's an itertools variant that is somewhat speedy when the inputlist
is long:

from itertools import *

def triple3(inputlist, list=list,
chain_from_iterable=chain.from_iterable, izip=izip):
return list(chain_from_iterable(izip(inputlist, inputlist,
inputlist)))

Raymond


Gabriel Genellina

unread,
Nov 16, 2009, 9:15:06 PM11/16/09
to pytho...@python.org
En Mon, 16 Nov 2009 19:30:27 -0300, Hyunchul Kim
<hyunchul...@gmail.com> escribi�:

> I want to improve speed of following simple function.
> Any suggestion?
>
> **********
> def triple(inputlist):
> results = []
> for x in inputlist:
> results.extend([x,x,x])
> return results

> **********

These are my best attempts:

def triple3(inputlist):
results = []
append = results.append
for x in inputlist:
append(x); append(x); append(x)
return results

def triple4(inputlist, _three=xrange(3)):
return [x for x in inputlist for _ in _three]

For a 400-items list, triple3 is 40% faster and triple4 25% faster than
yours.

--
Gabriel Genellina

Jason Sewall

unread,
Nov 16, 2009, 9:56:31 PM11/16/09
to Raymond Hettinger, pytho...@python.org

Even (slightly) faster:

def triple3_mk2(inputlist):
return list(chain.from_iterable(izip(*repeat(inputlist, 3))))

I tried something like this when I saw Hyunchul's original email, but
I didn't know about chain.from_iterable and it was pretty slow
compared to the original. Adding (itertools.)repeat to Raymonds
speeds it up 5-10% more.

I'm pretty surprised this is faster than Tim's t2 (which is actually a
little slower than the original); I always thought of comprehensions
as the fastest way to do this find of stuff.

Jason

Peter Otten

unread,
Nov 17, 2009, 5:24:18 AM11/17/09
to
Gabriel Genellina wrote:

> En Mon, 16 Nov 2009 19:30:27 -0300, Hyunchul Kim

> <hyunchul...@gmail.com> escribió:


>
>> I want to improve speed of following simple function.
>> Any suggestion?
>>
>> **********
>> def triple(inputlist):
>> results = []
>> for x in inputlist:
>> results.extend([x,x,x])
>> return results
>> **********
>
> These are my best attempts:
>
> def triple3(inputlist):
> results = []
> append = results.append
> for x in inputlist:
> append(x); append(x); append(x)
> return results
>
> def triple4(inputlist, _three=xrange(3)):
> return [x for x in inputlist for _ in _three]
>
> For a 400-items list, triple3 is 40% faster and triple4 25% faster than
> yours.

[I didn't see the original post]

If inputlist is actually a list or tuple the following should beat them all:

def triple_repeat(items):
result = [None] * (3*len(items))
result[::3] = result[1::3] = result[2::3] = items
return result

For small n the generalization should still be quite competitive:

def n_repeat(items, n):
items = tuple(items)
result = [None]*(len(items) * n)
for offset in range(n):
result[offset::n] = items
return result

Some measurements:

$ cat extend.py
from itertools import *

def triple_repeat(items):
result = [None] * (3*len(items))
result[::3] = result[1::3] = result[2::3] = items
return result

def n_repeat(items, n):
items = tuple(items)
result = [None]*(len(items) * n)
for offset in range(n):
result[offset::n] = items
return result

def t1(i):
for x in i:
yield x
yield x
yield x

def triple3(inputlist, list=list, chain_from_iterable=chain.from_iterable, izip=izip):
return list(chain_from_iterable(izip(inputlist, inputlist, inputlist)))

data = range(1000)


$ python -m timeit -s 'from extend import triple_repeat, data' 'triple_repeat(data)'
10000 loops, best of 3: 52.4 usec per loop
$ python -m timeit -s 'from extend import n_repeat, data' 'n_repeat(data, 3)'
10000 loops, best of 3: 60.7 usec per loop
$ python -m timeit -s 'from extend import t1, data' 'list(t1(data))'
1000 loops, best of 3: 337 usec per loop
$ python -m timeit -s 'from extend import triple3, data' 'triple3(data)'
1000 loops, best of 3: 231 usec per loop

Peter

0 new messages