3

Please understand, I searched for this and it already has an answer. However I'm looking for a different way to get this result. This could potentially be flagged as a duplicate although I think there is a cleaner answer for this possibly using itertools (most likely groupby).

Say I have a list data. And I want 3 values at a time assume the list is number of valuesⁿ long as to rule out improper amount of values at the end.

data = [1, 2, 3, 4, 5, 6,...]

Here's how I'd like to iterate through the list (this code wouldn't work obviously):

for a, b, c in data:
    #perform operations
    pass

Now with the code above I'd like a, b, c to be 1, 2, 3 then 4, 5, 6 respectively in each iteration. I'm sure there's a cleaner approach out there than the one in the answer I linked to.

For the lazy people that don't want to click on a link to see the approach I'm referring to, here it is:

You can use slices if you want to iterate through a list by pairs of successive elements:

>>>myList = [4, 5, 7, 23, 45, 65, 3445, 234]
>>>for x,y in (myList[i:i+2] for i in range(0,len(myList),2)):
print(x,y)

4 5
7 23
45 65
3445 234
Jab
  • 26,853
  • 21
  • 75
  • 114
  • dang marked as duplicate anyway. Didn't find that one. Although I did find [this](https://stackoverflow.com/a/434328/225020) answer the one I was trying to find. – Jab Jan 26 '19 at 00:58

2 Answers2

7

Here's a hacky solution with iter and zip:

i =  [1, 2, 3, 4, 5, 6]
d = iter(i)

for a, b, c in zip(*[d]*3):
    print(a, b, c)

Output:

1 2 3
4 5 6

Additionally if you want it to iterate over everything when your original list isn't divisible by three you can use zip_longest from itertools:

from itertools import zip_longest


i =  [1, 2, 3, 4, 5, 6, 7]
d = iter(i)

for a, b, c in zip_longest(*[d]*3):
  print(a, b, c)

Output:

1 2 3
4 5 6
7 None None
Primusa
  • 13,136
  • 3
  • 33
  • 53
  • I like this thanks! Now I want to see something along the lines of performance differences between this and something like @jspcal's approach – Jab Jan 26 '19 at 00:45
  • 2
    That's cool, having 3 copy of the same reference to the iterator in a list – Crivella Jan 26 '19 at 00:46
  • Note this solution is precisely the [`itertools` `grouper` recipe](https://docs.python.org/3/library/itertools.html#itertools-recipes) from the docs, also available in 3rd party [`more_itertools.grouper`](https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.grouper). – jpp Jan 26 '19 at 00:47
  • 2
    @Jaba jspcal's approach should be faster since I'm building a list, unpacking, and passing things into zip. However iterating over a list is already really fast, and my assumption is that your performance bottleneck will be what you will do with a, b, and c instead of just the iteration. – Primusa Jan 26 '19 at 00:49
  • While that's very true, I'm iterating over hundreds of millions of values in what I'm doing and will probably stick with what I have which is like @jspcal's approach I was only asking as it was peaking my interest due to another question I had seen earlier – Jab Jan 26 '19 at 00:51
  • @Jaba I did some timing here: https://repl.it/repls/UsefulSuperficialWorkers, for some reason my solution appears to be much faster. I think this is because it doesn't have to bind the values to variables during each cycle of the loop – Primusa Jan 26 '19 at 00:58
  • @Primusa I cannot load up repl.it at my station but I tried running [this](https://pastebin.com/LqNhpY8T) code using a simple `d=a+b+c` and your approach is giving a `TypeError` on the line `for a in d:` Saying that int isnt iterable? I added the addition because maybe it just wasn’t looking at all the code dude to the pass? – Jab Jan 26 '19 at 01:26
  • I’m dumb.... I reassign `d` right above it... change `d=a+b+c` to `v=a+b+c` – Jab Jan 26 '19 at 01:28
  • 1
    @Jaba the variant above is the fastest out of the three. Times are (3.5, 7, and 9.18 seconds). Note that you have a bug in your code where you use an already used up iterable to test the second variant. The times I got were after I fixed this bug. – Primusa Jan 26 '19 at 02:12
  • The replit link from above (https://repl.it/repls/UsefulSuperficialWorkers) has been updated to demonstrate the timings in my previous comment. – Primusa Jan 26 '19 at 02:14
  • Yes, yes it is! I ran it myself as well. It’s crazy that’s the fastest too I’m kinda taken back that it is. – Jab Jan 26 '19 at 06:28
1

Perhaps use an iterator and increment the iterator when you want the next element in the chunk:

data = [1, 2, 3, 4, 5, 6]
it = iter(data)

for x in it:
    a = x
    b = next(it)
    c = next(it)
    print(a, b, c)
    # Do something with a, b, and c
jspcal
  • 50,847
  • 7
  • 72
  • 76
  • Thank you, I do know this is a more traditional approach. unfortunately this is not what I'm looking for, I'd like to unpack it within the for declaration. – Jab Jan 26 '19 at 00:42