2

Given an iterator i, I want an iterator that yields each element n times, i.e., the equivalent of this function

def duplicate(i, n):
    for x in i:
        for k in range(n):
            yield x

Is there an one-liner for this?

Related question: duplicate each member in a list - python, but the zip solution doesn't work here.

Community
  • 1
  • 1
Tony Beta Lambda
  • 529
  • 3
  • 18

3 Answers3

6

This is my simple solution, if you want to duplicate each element same times. It returns a generator expression, which should be memory efficient.

def duplicate(i, n):
    return (k for k in i for j in range(n))

An example usage could be,

print (list(duplicate(range(1, 10), 3)))

Which prints,

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

Hossain Muctadir
  • 3,546
  • 1
  • 19
  • 33
4
itertools.chain.from_iterable(itertools.izip(*itertools.tee(source, n)))

Example:

>>> x = (a**2 for a in xrange(5))
>>> list(itertools.chain.from_iterable(itertools.izip(*itertools.tee(x, 3))))
[0, 0, 0, 1, 1, 1, 4, 4, 4, 9, 9, 9, 16, 16, 16]

Another way:

itertools.chain.from_iterable(itertools.repeat(item, n) for item in source)

>>> x = (a**2 for a in xrange(5))
>>> list(itertools.chain.from_iterable(itertools.repeat(item, 3) for item in x))
[0, 0, 0, 1, 1, 1, 4, 4, 4, 9, 9, 9, 16, 16, 16]
BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • Don't star the argument to `itertools.chain()`. Use `itertools.chain.from_iterable()` instead. – Kevin Mar 15 '16 at 04:27
  • Is this the same thing? I mean, according to the function in question, he call call `duplicate` function multiple time with a different number for each element. – Hossain Muctadir Mar 15 '16 at 04:32
  • Thanks for the `tee` recipe! The docs say "This (`tee`) itertool may require significant auxiliary storage", but in this actual use case it seems okay? Can you explain a bit? – Tony Beta Lambda Mar 15 '16 at 04:33
  • 1
    @TonyBetaLambda: As described in the docs, `tee` will use a lot of storage if you use a lot of one of the duplicates while not using the others. In this example that is not a concern because all duplicates are advanced in sync (i.e., you get the first element from all of them before getting the second from any of them). – BrenBarn Mar 15 '16 at 04:35
1

Use a generator expression:

>>> x = (n for n in range(4))
>>> i = (v for v in x for _ in range(3))
>>> list(i)
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3]
ekhumoro
  • 115,249
  • 20
  • 229
  • 336