Detect last iteration over dictionary.iteritems() in python
Question:
Is there a simple way to detect the last iteration while iterating over a dictionary using iteritems()
?
Answers:
No. When using an iterator you do not know anything about the position – actually, the iterator could be infinite.
Besides that, a dictionary is not ordered. So if you need it e.g. to insert commas between the elements you should take the items, sort them and them iterate over the list of (key, value)
tuples. And when iterating over this list you can easily count the number of iterations and thus know when you have the last element.
There is an ugly way to do this:
for i, (k, v) in enumerate(your_dict.items()):
if i == len(your_dict)-1:
# do special stuff here
But you should really consider if you need this. I am almost certain that there is another way.
it = spam_dict.iteritems()
try:
eggs1 = it.next()
while True:
eggs2 = it.next()
do_something(eggs1)
eggs1 = eggs2
except StopIteration:
do_final(eggs1)
Quick and quite dirty. Does it solve your issue?
as others have stated, dictionaries have no defined order, so it’s hard to imagine why you would need this, but here it is
last = None
for current in your_dict.iteritems():
if last is not None:
# process last
last = current
# now last contains the last thing in dict.iteritems()
if last is not None: # this could happen if the dict was empty
# process the last item
The approach that makes the most sense is to wrap the loop in some call which contains a hook to call your post-iteration functionality afterwards.
This could be implemented as context manager and called through a ‘with’ statement or, for older versions of Python, you could use the old ‘try:’ … ‘finally:’ construct. It could also be wrapped in a class where the dictionary iteration is self dispatched (a “private” method) and the appendix code follows that in the public method. (Understanding that the distension between public vs private is a matter of intention and documentation, not enforced by Python).
I recently had this issue, I thought this was the most elegant solution because it allowed you to write for i,value,isLast in lastEnumerate(...):
:
def lastEnumerate(iterator):
x = list(iterator)
for i,value in enumerate(x):
yield i,value,i==len(x)-1
For example:
for i,value,isLast in lastEnumerate(range(5)):
print(value)
if not isLast:
print(',')
This is a special case of this broader question. My suggestion was to create an enumerate-like generator that returns -1 on the last item:
def annotate(gen):
prev_i, prev_val = 0, gen.next()
for i, val in enumerate(gen, start=1):
yield prev_i, prev_val
prev_i, prev_val = i, val
yield '-1', prev_val
Add gen = iter(gen)
if you want it to handle sequences as well as generators.
The last item in a for loop hangs around after the for loop anyway:
for current_item in my_dict:
do_something(current_item)
try:
do_last(current_item)
except NameError:
print "my_dict was empty"
Even if the name “current_item” is in use before the for loop, attempting to loop over an empty dict seems to have the effect of deleting current_item, hence the NameError
You stated in an above comment that you need this to construct the WHERE clause of an SQL SELECT statement. Perhaps this will help:
def make_filter(colname, value):
if isinstance(value, str):
if '%' in value:
return "%s LIKE '%s'" % (colname, value)
else:
return "%s = '%s'" % (colname, value)
return "%s = %s" % (colname, value)
filters = {'USER_ID':'123456', 'CHECK_NUM':23459, 'CHECK_STATUS':'C%'}
whereclause = 'WHERE '+'nAND '.join(make_filter(*x) for x in filters.iteritems())
print whereclause
which prints
WHERE CHECK_NUM = 23459
AND CHECK_STATUS LIKE 'C%'
AND USER_ID = '123456'
I know this late, but here’s how I’ve solved this issue:
dictItemCount = len(dict)
dictPosition = 1
for key,value in dict
if(dictPosition = dictItemCount):
print 'last item in dictionary'
dictPosition += 1
Another approach is to enumerate your dict and compare the current iteration against the final one. Its easier to look at and understand in my opinion:
for n, (key, value) in enumerate(yourDict.items()):
if yourDict[n] == yourDict[-1]:
print('Found the last iteration!:', n)
OR you could just do something once the iteration is finished:
for key, value in yourDict.items():
pass
else:
print('Finished iterating over `yourDict`')
Is there a simple way to detect the last iteration while iterating over a dictionary using iteritems()
?
No. When using an iterator you do not know anything about the position – actually, the iterator could be infinite.
Besides that, a dictionary is not ordered. So if you need it e.g. to insert commas between the elements you should take the items, sort them and them iterate over the list of (key, value)
tuples. And when iterating over this list you can easily count the number of iterations and thus know when you have the last element.
There is an ugly way to do this:
for i, (k, v) in enumerate(your_dict.items()):
if i == len(your_dict)-1:
# do special stuff here
But you should really consider if you need this. I am almost certain that there is another way.
it = spam_dict.iteritems()
try:
eggs1 = it.next()
while True:
eggs2 = it.next()
do_something(eggs1)
eggs1 = eggs2
except StopIteration:
do_final(eggs1)
Quick and quite dirty. Does it solve your issue?
as others have stated, dictionaries have no defined order, so it’s hard to imagine why you would need this, but here it is
last = None
for current in your_dict.iteritems():
if last is not None:
# process last
last = current
# now last contains the last thing in dict.iteritems()
if last is not None: # this could happen if the dict was empty
# process the last item
The approach that makes the most sense is to wrap the loop in some call which contains a hook to call your post-iteration functionality afterwards.
This could be implemented as context manager and called through a ‘with’ statement or, for older versions of Python, you could use the old ‘try:’ … ‘finally:’ construct. It could also be wrapped in a class where the dictionary iteration is self dispatched (a “private” method) and the appendix code follows that in the public method. (Understanding that the distension between public vs private is a matter of intention and documentation, not enforced by Python).
I recently had this issue, I thought this was the most elegant solution because it allowed you to write for i,value,isLast in lastEnumerate(...):
:
def lastEnumerate(iterator):
x = list(iterator)
for i,value in enumerate(x):
yield i,value,i==len(x)-1
For example:
for i,value,isLast in lastEnumerate(range(5)):
print(value)
if not isLast:
print(',')
This is a special case of this broader question. My suggestion was to create an enumerate-like generator that returns -1 on the last item:
def annotate(gen):
prev_i, prev_val = 0, gen.next()
for i, val in enumerate(gen, start=1):
yield prev_i, prev_val
prev_i, prev_val = i, val
yield '-1', prev_val
Add gen = iter(gen)
if you want it to handle sequences as well as generators.
The last item in a for loop hangs around after the for loop anyway:
for current_item in my_dict:
do_something(current_item)
try:
do_last(current_item)
except NameError:
print "my_dict was empty"
Even if the name “current_item” is in use before the for loop, attempting to loop over an empty dict seems to have the effect of deleting current_item, hence the NameError
You stated in an above comment that you need this to construct the WHERE clause of an SQL SELECT statement. Perhaps this will help:
def make_filter(colname, value):
if isinstance(value, str):
if '%' in value:
return "%s LIKE '%s'" % (colname, value)
else:
return "%s = '%s'" % (colname, value)
return "%s = %s" % (colname, value)
filters = {'USER_ID':'123456', 'CHECK_NUM':23459, 'CHECK_STATUS':'C%'}
whereclause = 'WHERE '+'nAND '.join(make_filter(*x) for x in filters.iteritems())
print whereclause
which prints
WHERE CHECK_NUM = 23459
AND CHECK_STATUS LIKE 'C%'
AND USER_ID = '123456'
I know this late, but here’s how I’ve solved this issue:
dictItemCount = len(dict)
dictPosition = 1
for key,value in dict
if(dictPosition = dictItemCount):
print 'last item in dictionary'
dictPosition += 1
Another approach is to enumerate your dict and compare the current iteration against the final one. Its easier to look at and understand in my opinion:
for n, (key, value) in enumerate(yourDict.items()):
if yourDict[n] == yourDict[-1]:
print('Found the last iteration!:', n)
OR you could just do something once the iteration is finished:
for key, value in yourDict.items():
pass
else:
print('Finished iterating over `yourDict`')