5

For example, how to convert [1, 5, 7] into [1,2,5,6,7,8] into python? [x, x+1 for x in [1,5,7]] can't work for sure...

Nan Hua
  • 3,414
  • 3
  • 17
  • 24

7 Answers7

3

Not sure if this is the best way, but I would do:

l = [1, 5, 7]
print([y for x in l for y in (x, x + 1)])

Another way using itertools.chain.from_iterable:

from itertools import chain
l = [1, 5, 7]
print(list(chain.from_iterable((x, x + 1) for x in l)))
Karin
  • 8,404
  • 25
  • 34
2

And you can always overcomplicate the problem with operator, imap(), partial(), izip() and chain():

>>> from itertools import chain, izip, imap
>>> from operator import add
>>> from functools import partial
>>> 
>>> l = [1, 5, 7]
>>>
>>> list(chain(*izip(l, imap(partial(add, 1), l))))
[1, 2, 5, 6, 7, 8]

What happens here:

  • we make an iterator over l that applies an add function with 1 as an argument
  • we zip the initial list with the iterator returned by imap() to produce pairs of x, x+1 values
  • we flatten the list with chain() and convert it to the list to see the result
Community
  • 1
  • 1
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • 3
    Haha this is hideous ;) – 101 Aug 30 '16 at 02:08
  • Yeah, I don't understand the downvote though. This is a working solution *with an explanation*, links to docs and it even says I understand this is an over-complication of a sort. – alecxe Aug 30 '16 at 03:56
2

A simple way to think about the problem is to make a second list of incremented values and add it to the original list, then sort it:

l = [1, 5, 7]
m = l + [i+1 for i in l]
m.sort()
print m  # [1, 2, 5, 6, 7, 8]
101
  • 8,514
  • 6
  • 43
  • 69
2

You can combine some ideas from alecxe's answer and what you already had:

>>> import itertools
>>> 
>>> a = [1, 5, 7]
>>> b = ((x, x+1) for x in a)
>>> 
>>> list(itertools.chain(*b))
[1, 2, 5, 6, 7, 8]

What I have done is :

  1. Define in b a generator expression which allows us to have (something that looks like) a tuple that would have looked like ((1, 2), (5, 6), (7, 8)) but without evaluating it right away. It would have also worked with a list comprehension.

  2. Unpack b in the argument list of itertools.chain(). It would be the equivalent of itertools.chain((1, 2), (5, 6), (7, 8)). That function concatenates its arguments.

  3. Use list() to create a list from the return value of the itertools.chain() function since it's an iterator.

This could also have worked without any intermediate step:

>>> import itertools
>>> list(itertools.chain(*((x, x+1) for x in [1, 5, 7])))
[1, 2, 5, 6, 7, 8]

But "Simple is better than complex"

I hope this helps.

I would have put more links if I had more reputation, sorry.

EvensF
  • 1,479
  • 1
  • 10
  • 17
2

Make a generator function that iterates over the list and yields, in turn, each element and that element plus one. Iterate over your generator.

def foo(lyst):
    for element in lyst:
        yield element
        yield element + 1

>>> print(list(foo([1, 5, 7])))
[1, 2, 5, 6, 7, 8]
>>> 
>>> print([element for element in foo([1, 5, 7])])
[1, 2, 5, 6, 7, 8]
>>>
wwii
  • 23,232
  • 7
  • 37
  • 77
1

You can do your list comprehension logic with tuples and then flatten the resulting list:

[n for pair in [(x, x+1) for x in [1,5,7]] for n in pair]

Gall
  • 38
  • 4
0

If you just want to fill the list with the numbers between the min and max+1 values you can use [i for i in range (min(x),max(x)+2)] assuming x is your list.

Kevin K.
  • 1,327
  • 2
  • 13
  • 18