How to write a generator that returns ALL-BUT-LAST elements in iterable in Python?

I asked a few similar questions [1, 2] yesterday and received excellent answers, but I am not technically sufficient enough to write a generator of such complexity.

How can I write a generator that will call StopIteration if it is the last element instead of yielding to it?

I think I need to somehow set two values ​​at a time and see if the second value is StopIteration. If so, then instead of giving way to the first value, I have to raise this StopIteration. But for some reason, I also have to remember the second value, which I asked if it was not StopIteration.

I don’t know how to write it myself. Please, help.

For example, if iterability is [1, 2, 3], then the generator should return 1 and 2.

Thanks, Boda Sido.

[1] How to change the generator in Python?

[2] How to determine if a value is ONE-BUT-LAST in a Python generator?

+4
source share
5 answers

This should do the trick:

def allbutlast(iterable): it = iter(iterable) current = it.next() for i in it: yield current current = i >>> list(allbutlast([1,2,3])) [1, 2] 

This will scroll through the entire list and return the previous item so that the last item never returns.
Note that calling the above on both [] and [1] will return an empty list.

+11
source

First, do I need a generator? This sounds like the perfect work for Pythons fragment syntax :

 result = my_range[ : -1] 

Ie: accept the range from the first element to the last.

+2
source

the itertools module shows the pairwise() method in its recipes. adapting from this recipe, you can get your generator:

 from itertools import * def n_apart(iterable, n): a,b = tee(iterable) for count in range(n): next(b) return zip(a,b) def all_but_n_last(iterable, n): return (value for value,dummy in n_apart(iterable, n)) 

n_apart() returns return pairs of values ​​that are n elements separately in the input iterable, ignoring all pairs. all_but_b_last() returns the first value of all pairs, which accidentally ignores the n last list items.

 >>> data = range(10) >>> list(data) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> list(n_apart(data,3)) [(0, 3), (1, 4), (2, 5), (3, 6), (4, 7), (5, 8), (6, 9)] >>> list(all_but_n_last(data,3)) [0, 1, 2, 3, 4, 5, 6] >>> >>> list(all_but_n_last(data,1)) [0, 1, 2, 3, 4, 5, 6, 7, 8] 
+1
source

The more_itertools project has a tool that emulates itertools.islice with support for negative indexes:

 import more_itertools as mit list(mit.islice_extended([1, 2, 3], None, -1)) # [1, 2] 
0
source
 gen = (x for x in iterable[:-1]) 
-1
source

Source: https://habr.com/ru/post/1303793/


All Articles