1

I'm working on the following code:

mylist = [1,2,3,4,5,6,7,8,9,10.....]
for x in range(0, len(mylist), 3):
    value = mylist[x:x + 3]
    print(value)

Basically, I'm taking 3 items in mylist at a time, the code is bigger than that, but I'm doing a lot of things with them returning a value from it, then it takes the next 3 items from mylist and keep doing it till the end of this list.

But now I have a problem, I need to identify each iteration, but they follow a rule:

The first loop are from A, the second are from B and the third are from C. When it reaches the third, it starts over with A, so what I'm trying to do is something like this:

mylist[0:3] are from A

mylist[3:6] are from B

mylist[6:9] are from C

mylist[9:12]are from A

mylist[12:15] are from B......

The initial idea was to implement a identifier the goes from A to C, and each iteration it jumps to the next identifier, but when it reaches C, it backs to A.

So the output seems like this:

[1,2,3] from A
[4,5,6] from B
[6,7,8] from C
[9,10,11] from A
[12,13,14] from B
[15,16,17] from C
[18,19,20] from A.....

My bad solution: Create identifiers = [A,B,C] multiply it by the len of mylist -> identifiers = [A,B,C]*len(mylist) So the amount of A's, B's and C's are the same of mylist numbers that it needs to identify. Then inside my for loop I add a counter that adds +1 to itself and access the index of my list.

mylist = [1,2,3,4,5,6,7,8,9,10.....]
identifier = ['A','B','C']*len(mylist)
counter = -1
for x in range(0, len(mylist), 3):

    value = mylist[x:x + 3]
    counter += 1
    print(value, identifier[counter])

But its too ugly and not fast at all. Does anyone know a faster way to do it?

quamrana
  • 37,849
  • 12
  • 53
  • 71
Bruno Cerk
  • 355
  • 3
  • 16

4 Answers4

4

Cycle, zip, and unpack:

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

for value, iden in zip(mylist, itertools.cycle('A', 'B', 'C')):
    print(value, iden)

Output:

1 A
2 B
3 C
4 A
5 B
6 C
7 A
8 B
9 C
10 A
quamrana
  • 37,849
  • 12
  • 53
  • 71
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • Maybe it needs to do some reshape of my list before in order to get n rows and 3 columns (to exactly fit the expected result)? what do you think? – David Leon Mar 06 '18 at 18:34
2

You can always use a generator to iterate over your identifiers:

def infinite_generator(seq):
    while True:
        for item in seq:
            yield item

Initialise the identifiers:

identifier = infinite_generator(['A', 'B', 'C'])

Then in your loop:

print(value, next(identifier))
quamrana
  • 37,849
  • 12
  • 53
  • 71
  • Which is bascially the same as [`itertools.cycle`](https://docs.python.org/3/library/itertools.html#itertools.cycle). – Graipher Mar 06 '18 at 15:41
1

Based on Ignacio's answer fitted for your problem.
You can first reshape your list into a list of arrays containing 3 elements:

import pandas as pd
import numpy as np
import itertools

mylist = [1,2,3,4,5,6,7,8,9,10]
_reshaped = np.reshape(mylist[:len(mylist)-len(mylist)%3],(-1,3))

print(_reshaped)
[[1 2 3]
 [4 5 6]
 [7 8 9]]

Note that it works since your list contains multiple of 3 elements (so you need to drop the last elements in order to respect this condition, mylist[:len(mylist)-len(mylist)%3]) - Understanding slice notation
See UPDATE section for a reshape that fits to your question.

Then apply Ignacio's solution on the reshaped list

for value, iden in zip(_reshaped, itertools.cycle(('A', 'B', 'C'))):
    print(value, iden)

[1 2 3] A
[4 5 6] B
[7 8 9] C

UPDATE
You can use @NedBatchelder's chunk generator to reshape you array as expected:

def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in range(0, len(l), n):
        yield l[i:i + n]

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

_reshaped = list(chunks(mylist, 3))
print(_reshaped)
    [[1 2 3]
     [4 5 6]
     [7 8 9]
     [10]]

Then:

for value, iden in zip(_reshaped, itertools.cycle(('A', 'B', 'C'))):
    print(value, iden)

[1 2 3] A
[4 5 6] B
[7 8 9] C
[10] A

Performances

Your solution : 1.32 ms ± 94.3 µs per loop
With a reshaped list : 1.32 ms ± 84.6 µs per loop

You notice that there is no sensitive difference in terms of performances for an equivalent result.

David Leon
  • 1,017
  • 8
  • 25
  • Thanks for the timing results, i was not expecting a big amount of difference, but as my main goal here is performance, because the final objective has been reached anyway, every improvement would be welcome – Bruno Cerk Mar 16 '18 at 03:26
  • I'm using the generator from itertools with next(generator) function, it proved to be faster then what i was doing, i'm going to try your solution and see what is faster – Bruno Cerk Mar 16 '18 at 03:27
0

You could create a Generator for the slices:

grouped_items = zip(*[seq[i::3] for i in range(3)])
pask
  • 899
  • 9
  • 19