0

I have a large sequence related problem to solve for which following is sub problem, an I am sure its something very basic in python that I am not aware of.

seq = [4*x for x in range (1,(20/4))]
generates seq = [4, 8, 12, 16]

How can I generate

[4, 4, 8, 8, 12, 12, 16]

seq = [4*x, 4*x for x in range (1,(20/4))] does not work

I can easily solve above problem by writing a small function, but I require it at the variable definition time.

3
  • 1
    Is 16 meant to only be there once? Commented Feb 2, 2013 at 18:30
  • As the OP on their last line tried ... 4*x, 4*x ... I think that your solution would be correct. Commented Feb 2, 2013 at 18:37
  • yes, solution was incorrect. Commented Feb 2, 2013 at 18:40

4 Answers 4

7

Your solution doesn't work because it produces a list of tuples.

What you are looking for is a way to flatten the list you produce - the simplest way to do this is itertools.chain.from_iterable():

>>> list(itertools.chain.from_iterable([4*x]*2 for x in range(1, 5)))
[4, 4, 8, 8, 12, 12, 16, 16]

If you intended to have the last value only once, as in your example, simply slice the end of the list (seq[:-1]).

As a note, rather than repeating your value for each repetition you want, you can use a list and multiply it up (providing the values are immutable, or you don't mind them being the same object). An alternative is itertools.repeat().

Sign up to request clarification or add additional context in comments.

Comments

0

A variation of @shantanoo's answer:

[ 4 * i for s in itertools.izip(*itertools.tee(range(1,5))) for i in s]

Output

[4, 4, 8, 8, 12, 12, 16, 16]

Really it was just an excuse to use itertools.tee :D

Comments

0

Sometimes a simple generator is all it takes:

def doubler_almost(seq):
    """
    Yield elements from a sequence twice until the last element
    which is only yielded once
    """
    iseq = iter(seq)
    y = next(iseq)
    yield y
    for x in iseq:
        yield y
        yield x
        y = x

print list(doubler_almost(range(4,20,4)))

-- Although this generator could definitely benefit from a better name...

The thing you get from this answer that you don't get from the others is that you don't need to convert to a list in order to slice off the last element -- It can be evaluated completely lazily. It also can be passed a generator and it still works (although the answer by Lattyware still works in that case as well -- but the zip answers don't unless you use itertools.tee first).

Comments

0

Another way:

>>> seq = [4, 8, 12, 16]
>>> seq = [i for s in zip(seq,seq) for i in s]
>>> seq
[4, 4, 8, 8, 12, 12, 16, 16]

In case of seq as iter,

>>> seq = [4, 8, 12, 16]
>>> seq = [i for s in zip(seq,seq.copy()) for i in s]
>>> seq
[4, 4, 8, 8, 12, 12, 16, 16]

Thanks @mgilson for the iter feedback.

2 Comments

I would note that using a list comprehension like this to flatten a sequence is less efficient than itertools.chain.from_iterable().
this also doesn't work if seq is a generator. e.g. seq = iter([4,8,12,16])

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.