1

I have got 2 lists: A=[0, 1, 2, 3, 4] and B=[3, 2, 5, 2, 4] and would like to repeat every ith element of A B[i] times, so for given lists it would be:

repA = [ 0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 3, 3, 4, 4, 4, 4] so now we have three 0, two 1, five 2 and so on. I found that duplicating solution but have no idea how to do it for different times (writen in B list)

Their code is like [ item for item in list for _ in range(repetition) ]

4 Answers4

1

You just need to use zip to pair items with counts, then use the count to determine how many times to repeat the item. It ends up very similar to the example code you provided.

[item for item, count in zip(A, B) for _ in range(count)]
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
1

If you would like to do this in a lazily-evaluated, functional way, you can use a couple tools from itertools to do this:

from itertools import repeat, starmap, chain

A = [0, 1, 2, 3, 4]
B = [3, 2, 5, 2, 4]

c = chain.from_iterable(starmap(repeat, zip(A, B)))

# evaluate
print(list(c))
# [0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 3, 3, 4, 4, 4, 4]

This doesn't buy you much for a small list, but can be useful if you are starting with large input or the number of repetitions is large since you never need to create the entire list in memory if you don't want to.

The code above maps the input from the two lists to repeat(), and then uses chain.from_iterable() to flatten the output to a single iterator.

Mark
  • 90,562
  • 7
  • 108
  • 148
  • You *could* do that, but it's a lot more complex than just replacing the `[]` of a list comprehension with `()` to get a generator expression. – Karl Knechtel Apr 11 '21 at 23:36
  • I suppose it's a matter of style and opinion. I find the above more readable and the intention more obvious. Of course, YMMV. – Mark Apr 11 '21 at 23:43
  • Also, @KarlKnechtel, using itertools is *significantly* faster when either A or B are large. I suspect `range()` is the bottleneck. – Mark Apr 12 '21 at 00:01
  • Yes, over 5 times as fast in my testing. Good to know. I find it difficult to believe that the creation of the `range` objects itself is the bottleneck, since not that many of them are created and they're lazily evaluated. However, iterating over them - in particular, getting values from the range that are then thrown away to `_` - might be a problem. – Karl Knechtel Apr 12 '21 at 00:10
  • Further testing results: `chain.from_iterable` and `repeat` *both* need to be used to get a performant result; if either is replaced using the equivalent generator-expression mechanics, the performance is negligibly improved (or even made worse). However, `starmap` is irrelevant to the performance boost. Thus `chain.from_iterable(repeat(a, b) for a, b in zip(A, B))` works almost as well. – Karl Knechtel Apr 12 '21 at 00:28
0

Perhaps try something like this:

A=[0, 1, 2, 3, 4]
B=[3, 2, 5, 2, 4]

res = []
for num, mult in zip(A, B):
    res.extend([num]*mult)

print(res)

What happens when we zip A and B and unpack it into num and mult, it says pair the first num in A with the furst mult in B. Same for the second, third and so on.

Then [num]*mult returns say [3]*5 = [3,3,3,3,3].

And when .extend is used for a list it simply extends the list by the argument.

res = [0, 0, 0] so res.extend([3,3,3,3,3]) gives us res = [0,0,0,3,3,3,3,3].

LPR
  • 400
  • 1
  • 8
0

I found that duplicating solution but have no idea how to do it for different times (writen in B list)

Well, how does the existing code determine the number of repetitions? From the constant value repetition, right? So, what you need is to replace that with a corresponding element of B for each of the elements from A being repeated, yeah? So, the problem boils down to iterating over those two lists in parallel.

So, given

A = [0, 1, 2, 3, 4]
B = [3, 2, 5, 2, 4]

We want: the a element, for each of the a, b pairs that we get by zipping together A and B (iterating over them in parallel), repeated b times.

I structured that description to match the corresponding list comprehension:

[a for a, b in zip(A, B) for _ in range(b)]

which we can mechanically translate into the corresponding for loops:

result = []
for a, b in zip(A, B):
    for _ in range(b):
        result.append(a)

Translating from a comprehension into procedural code, the for (and if, where applicable) clauses appear in the same order, and the thing being appended moves from the front into the innermost block.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153