23

Say I have a list of tuples like [(1,2), (1,3), (1,4), (1,5), (1,6)]. I'm trying to convert it to a simple list like [1,2,1,3,1,4,1,5,1,6].

How do I do this without having to iterate through each element and add the items one by one to another list?

Are there any fast and efficient ways to do this without actually iterating through the original list of tuples? Perhaps a built-in function or method?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
davidadamojr
  • 367
  • 1
  • 2
  • 8
  • I don't think there is a way to do it without _implicitly_ iterating through the tuples. – mjgpy3 Sep 10 '12 at 16:11
  • @jonathanmarvens: I think by "without having to iterate through each element`, the OP meant using an explicit for loop. – David Robinson Sep 10 '12 at 16:23
  • Of course, "`[e for l in lst for e in l]`" (from David Robinson's answer) is the fastest way to do it, but I think it would be impossible to do this "_without [implicitly] actually iterating through the original list of tuples_". Even if you use some "_built-in function/method_", that's what it has to do under-the-hood. – jonathanmarvens Sep 10 '12 at 16:24
  • @DavidRobinson OK. I just wanted to make sure he understands that. – jonathanmarvens Sep 10 '12 at 16:25
  • I understand there is probably no way to do it without IMPLICITLY iterating through the tuples. @DavidRobinson is right. I was trying to avoid EXPLICITLY using a 'for' loop. – davidadamojr Sep 10 '12 at 16:26
  • @jonathanmarvens "[e for l in lst for e in l]" just might be more efficient since I do not have to import a module or make a function call. Also, I get to write a single line of code. Great! – davidadamojr Sep 10 '12 at 16:30
  • Fundamentally, which one is faster? Using the "itertools" module, or using a list comprehension? I'm basically trying to improve my computation speed here. – davidadamojr Sep 10 '12 at 16:45
  • @davidadamojr When I said "_faster_", I wasn't talking about efficiency, I meant _faster_ **to write**. LOL. – jonathanmarvens Sep 10 '12 at 18:00

4 Answers4

39
lst = [(1,2), (1,3), (1,4), (1,5), (1,6)]

import itertools
list(itertools.chain(*lst))
# [1, 2, 1, 3, 1, 4, 1, 5, 1, 6]

Alternatively:

[e for l in lst for e in l]
# [1, 2, 1, 3, 1, 4, 1, 5, 1, 6]
David Robinson
  • 77,383
  • 16
  • 167
  • 187
  • I sure will. I am also gonna try the list comprehension. I have a couple of benchmarks I'm running. It just might get my work done faster since I won't import any module. @ovgolovin also suggested something below that I'd try out to see if it's faster. – davidadamojr Sep 10 '12 at 16:36
  • @davidadamojr According to [this excellent answer](http://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-python/952952#952952), the list comprehension version is faster. – David Robinson Sep 10 '12 at 17:03
  • @DavidRobinson They have made a lot of optimizations since the time of that answer. A lot may have changed since. Especially major speed-related changes were in Python 3. To be sure, speed test should be performed in the current version of Python that one uses. – ovgolovin Sep 10 '12 at 20:10
  • @DavidRobinson Here is the article by BDFL where he writes about it: http://python-history.blogspot.com/2010/06/from-list-comprehensions-to-generator.html – ovgolovin Sep 10 '12 at 20:15
12

Fundamentally, which one is faster? Using the "itertools" module, or using a list comprehension? I'm basically trying to improve my computation speed here. - @davidadamojr

I've been doing some tests and I find that the code below is actually faster.

list_ = [(1, 2), (1, 3), (1, 4), (1, 5), (1, 6)]
list(sum(list_, ()))

Someone correct me if I'm wrong.

Here are some tests below.

>>> list_ = [(1, 2), (1, 3), (1, 4), (1, 5), (1, 6)]
>>> 
>>> operation_1 = lambda: [tuple_item for tuple_ in list_ for tuple_item in tuple_]
>>> def operation_2 ():
        final_list = []
        for tuple_ in list_:
            for tuple_item in tuple_:
                final_list.append(tuple_item)
        return final_list

>>> operation_3 = lambda: reduce(list.__add__, map(list, list_))
>>> def operation_4 ():
        import itertools
        return list(itertools.chain(*list_))

>>> operation_5 = lambda: list(sum(list_, ()))
>>> 
>>> operation_1()
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]
>>> operation_2()
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]
>>> operation_3()
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]
>>> operation_4()
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]
>>> operation_5()
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]
>>> 
>>> import timeit
>>> 
>>> print('operation_1 completed in %s seconds.' % (timeit.timeit(operation_1)))
operation_1 completed in 1.57890490223 seconds.
>>> print('operation_2 completed in %s seconds.' % (timeit.timeit(operation_2)))
operation_2 completed in 2.90350501659 seconds.
>>> print('operation_3 completed in %s seconds.' % (timeit.timeit(operation_3)))
operation_3 completed in 5.08437990236 seconds.
>>> print('operation_4 completed in %s seconds.' % (timeit.timeit(operation_4)))
operation_4 completed in 3.85125378138 seconds.
>>> print('operation_5 completed in %s seconds.' % (timeit.timeit(operation_5)))
operation_5 completed in 1.2623826489 seconds.
jonathanmarvens
  • 402
  • 1
  • 3
  • 10
  • And of course, none of these operations flatten recursively. They only flatten at a single level. To avoid rewriting something that someone else has done, click [here](http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html) to visit an article on recursive flattening. It's an old article (from 2006), but I don't think that should be an issue. – jonathanmarvens Sep 10 '12 at 17:55
  • 1
    Hey @jonathanmarvens, I ran the tests also and indeed operation_5 seems the fastest. Great! – davidadamojr Sep 10 '12 at 18:43
  • @davidadamojr I'm glad it works for you! If you don't mind, I would appreciate it if you would vote up my answer. Thanks. – jonathanmarvens Sep 10 '12 at 19:02
8

Use chain.from_iterable, as it avoids unnecessary all-at-once unpacking (which leads to redundant memory consumption) by lazily advancing through list:

>>> import itertools
>>> L = [(1,2), (1,3), (1,4), (1,5), (1,6)]
>>> list(itertools.chain.from_iterable(L))
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]
ovgolovin
  • 13,063
  • 6
  • 47
  • 78
1

Here is the best way to do it in terms of performance and independence of special modules like itertools:

>>> l = [(1,2), (1,3), (1,4), (1,5), (1,6)] 
>>> reduce(list.__add__,map(list,l))
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]
Pupkov-Zadnij
  • 1,342
  • 2
  • 11
  • 21