for loop using enumerate terminates unexpectedly - python

Here is a simple for loop through an enumerate object. This terminates due to (this line I have mentioned as a comment). Why is that?
enum_arr = enumerate(arr)
for ele in enum_arr:
print(ele)
print(list(enum_arr)[ele[0]:]) # terminates due to this line
Output:
(0, 0)
[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]
If I comment out the second print statement, then:
Output:
(0, 0)
(1, 1)
(2, 2)
(3, 3)
(4, 4)
(5, 5)
As expected.
Why is this happening?

enumerate() gives you an iterator object. Iterators are like a bookmark in a book that can only be moved forward; once you reach the end of the book you can't go back anymore, and have to make a new bookmark.
You then use that iterator in two places; the for loop and list(). The list() function moved the bookmark all the way to the end, so the for loop can't move it any further.
You'd have to create a new enumerate() object in the loop if you want to use a separate, independent iterator:
enum_arr = enumerate(arr)
for ele in enum_arr:
print(ele)
print(list(enumerate(arr[ele[0]:], ele[0])))
This does require that arr is itself not an iterator, it has to be a sequence so you can index into it. I'm assuming here that you have a list, tuple, range or similar value.
Note that I passed in ele[0] twice, the second argument to enumerate() lets you set the start value of the counter.
It is easier to use a tuple assignment here to separate out the count and value:
for count, value in enum_arr:
print((count, value))
print(list(enumerate(arr[count:], count)))
Demo:
>>> arr = range(6)
>>> enum_arr = enumerate(arr)
>>> for count, value in enum_arr:
... print((count, value))
... print(list(enumerate(arr[count:], count)))
...
(0, 0)
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]
(1, 1)
[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]
(2, 2)
[(2, 2), (3, 3), (4, 4), (5, 5)]
(3, 3)
[(3, 3), (4, 4), (5, 5)]
(4, 4)
[(4, 4), (5, 5)]
(5, 5)
[(5, 5)]
Coming back to the book analogy, and the requirement that arr is a sequence: as long as arr is a book with page numbers, you can add more bookmarks at any point. If it is some other iterable type, then you can't index into it and so would have to find some other means to 'skip ahead' and back again. Stretching the analogy further: say the book is being streamed to you, one page at a time, then you can't go back once you received all the pages. The solution coud be to create a local cache of pages first; if you can spare the memory that could be done with cached_copy = list(arr). Just take into account that you have to be sure that the book you are receiving is not so long as to require more space than you actually have. And some iterables are endless, so would require infinite memory!

Related

Number of passengers. Error: list indices must be integers or slices, not list

So, I'm trying to sum the number of passenger at each stop.
The "stops" variable are the number of stops, and is conformed by a tuple which contains the in's and out's of passengers, example:
stops = [(in1, out1), (in2, out2), (in3, out3), (in4, out4)]
stops = [(10, 0), (4, 1), (3, 5), (3, 4), (5, 1), (1, 5), (5, 8), (4, 6), (2, 3)]
number_passenger_per_stop = []
for i in stops:
resta = stops[i][0] - stops[i][1]
number_passenger_per_stop.append(resta)
print(number_passenger_per_stop)
I can do the math like this outside the loop, but I don't understand why in the loop crashes:
stops[i][0] - stops[i][1]
i is not the list index, it's the list element itself. You don't need to write stops[i].
resta = i[0] - i[1]
Your code would be correct if you had written
for i in range(len(stops)):
You could also replace the entire thing with a list comprehension:
number_passenger_per_stop = [on - off for on, off in stops]
I just edited the for loop to adress each in the index in the list correctly, you needed to call each element in the list by its position, and not by its value:
stops = [(10, 0), (4, 1), (3, 5), (3, 4), (5, 1), (1, 5), (5, 8), (4, 6), (2, 3)]
number_passenger_per_stop = []
for i in range(len(stops)):
resta = stops[i][0] - stops[i][1]
number_passenger_per_stop.append(resta)
print(number_passenger_per_stop)
Output:
[10, 3, -2, -1, 4, -4, -3, -2, -1]

How to iterate through a list of tuple within tuple in python?

Let's say I have a list like so: [(1, (1,2)), (2, (23, -10)), (3, (4, 5))...]
I want to get (1,2), (23, -10), etc
edit: Thanks for help. I didn't know about list comprehension as I'm not too familiar with python
Try Something like this:-
Here is List and get other list of tuples:-
a = [(1, (1,2)), (2, (23, -10)), (3, (4, 5))...]
b = map(lambda item: item[1], a)
print b
This will solve your problem.
Here is list of tuples where second elem of each tuple is also a tuple. To get that second elem we are going to use lambda that is going to take elements from list and just return second item from that element, in this case being desired tuple. The map function also creates a list of returned values.
>>> list_of_nested_tuples = [(1, (1, 2)), (2, (23, -10)), (3, (4, 5))]
>>> b = map(lambda item: item[1], list_of_nested_tuples)
>>> b
[(1, 2), (23, -10), (4, 5)]
Take note that it would be more clear to just use list comprehension like so
>>> [elem[1] for elem in list_of_nested_tuples]
[(1, 2), (23, -10), (4, 5)]
Yes, you can iterate over all tuples and then take the second element:
list = [(1, (1,2)), (2, (23, -10)), (3, (4, 5))]
for elem in list:
print(elem[1])
In each iteration elem value its (1,(1,2)) -> (2,(23,-10)) -> ....
Then you take the second item of the tuple (index 1)

Delete item in a list in Python [duplicate]

This question already has answers here:
Is there a simple way to delete a list element by value?
(25 answers)
Closed 7 years ago.
How to find and delete only one element in a list in Python?
# Example:deleting only the first (1,2) in the list
a = [(4, 5), (1, 2), (7, 5), (1, 2), (5, 2)]
# result expected
a = [(4, 5), (7, 5), (1, 2), (5, 2)]
Use the list.remove() method to remove the first occurrence, in-place:
a.remove((1, 2))
Demo:
>>> a = [(4, 5), (1, 2), (7, 5), (1, 2), (5, 2)]
>>> a.remove((1, 2))
>>> a
[(4, 5), (7, 5), (1, 2), (5, 2)]
See the Mutable Sequence Types documentation:
s.remove(x)
same as del s[s.index(x)]
and s.index() only ever finds the first occurrence.
Hello if you want to delete any thing in lists
use these codes
mylist.pop(element_order) #mylist stands for your list and
#element_order stands for the order of element is the list and if it is the
#first element it will be 0
or you can use
mylist.remove(the_element)
note that in the pop it is a method not a list
mylist.pop(0)
print mylist
dont use
mylist = mylist.pop(0)

returning a list of tuples like zip, generate it incrementally a tuple at a time, using comprehensions

I need a function which returns a tuple one at a time from a list of sequences without using zip . i tried to do it in this fashion:
gen1=[(x,y)for x in range(3) for y in range(4)]
which gives the following list:
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)]
next I tried to return one tuple at a time by:
next(gen1)
But an error occured that list is not 'iterable' . how can i do it using generators.
If you want the behavior to work with an arbitrary number of sequences, while there are still some ambiguities in the question, if what you're trying to do is just make a generator version of zip, the below should work well:
def generator_zip(*args):
iterators = map(iter, args)
while iterators:
yield tuple(map(next, iterators))
First it turns each arg into an iterator, then continues to yield tuple that include the next relevant entry from each iterator until the shortest list is exhausted.
As of Python 2.4, you can do:
gen1 = ((x, y) for x in range(3) for y in range(4))
Note that you can always make a generator (well, iterator) from a list with iter:
gen1 = iter([(x, y) for x in range(3) for y in range(4)])
The difference in usage will be none. The second way will require the whole list to be in memory, though, while the first will not.
Note that you can also use the builtin functionality of zip, which is a generator (in Python 3). In Python 2, use itertools.izip.
Python 3:
>>> zip(range(0, 5), range(3, 8))
<zip object at 0x7f07519b3b90>
>>> list(zip(range(0, 5), range(3, 8)))
[(0, 3), (1, 4), (2, 5), (3, 6), (4, 7)]
Python < 3:
# Python < 3
>>> from itertools import izip
>>> izip(range(0, 5), range(3, 8))
<itertools.izip object at 0x7f5247807440>
>>> list(izip(range(0, 5), range(3, 8)))
[(0, 3), (1, 4), (2, 5), (3, 6), (4, 7)]
>>> zip(range(0, 5), range(3, 8))
[(0, 3), (1, 4), (2, 5), (3, 6), (4, 7)]

Difficulty Sorting Tuples with itemgetter

I'm new to Python as the screen name attests. I was attempting to sort a list of tuples, think (x,y) pairs in a list and ran into a problem. My goal is to sort the list of tuples by the x variables in ascending order primarily but then sort
I investigated the wiki on HowToSort at http://wiki.python.org/moin/HowTo/Sorting/ and thought I would try the operator module and the itemgetter function as a key.
The simple sorted() function can sort the tuple fine, but when you want one index ascending and one ascending, I'm lost. Here is the code:
from operator import itemgetter, attrgetter
ItemList = [(1,7),(2,1),(1,5),(1,1)]
# Want list sorted with X values descending, then y values ascending
# expected [(2, 1), (1, 1), (1,5), (1, 7)]
print
print ' Input:', ItemList
print 'Output1:',sorted(ItemList, reverse = True)
print
print ' Input:', ItemList
print 'Output2:', sorted(ItemList, key = itemgetter(-0,1))
print
print ' WANTED:', '[(2, 1), (1, 1), (1,5), (1, 7)]'
with the following output:
Input: [(1, 7), (2, 1), (1, 5), (1, 1)]
Output1: [(2, 1), (1, 7), (1, 5), (1, 1)]
Input: [(1, 7), (2, 1), (1, 5), (1, 1)]
Output2: [(1, 1), (1, 5), (1, 7), (2, 1)]
WANTED: [(2, 1), (1, 1), (1, 5), (1, 7)]
I obviously, do not understand the itemgetter function, so any help would be appreciated on that.
Also, any ideas on how to do the two sort on (x,y) pairs? I am hoping to avoid a lambda solution but I'm sure that's where this is going. Thanks.
-0 is the same thing as 0. More-over, negative indices have a different meaning to itemgetter(); it does not mean that the values are negated.
Use a lambda instead:
sorted(ItemList, key=lambda item: (-item[0], item[1]))
Demo:
>>> ItemList = [(1,7),(2,1),(1,5),(1,1)]
>>> sorted(ItemList, key=lambda item: (-item[0], item[1]))
[(2, 1), (1, 1), (1, 5), (1, 7)]
Negative indices take items from the end of a sequence:
>>> end = itemgetter(-1)
>>> end([1, 2, 3])
3
The itemgetter() will never modify the retrieved item, certainly not negate it.
Note that itemgetter() is only a convenience method, you do not have to use it and for more complex sorting orders, a custom function or lambda is the better choice.

Categories

Resources