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()?

Asked By: kadam

||

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.

Answered By: ThiefMaster

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.

Answered By: Björn Pollex
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?

Answered By: Evpok

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
Answered By: Bwmat

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).

Answered By: Jim Dennis

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(',')
Answered By: ninjagecko

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.

Answered By: senderle

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

Answered By: nakedfanatic

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'
Answered By: Steven Rumbalski

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
Answered By: user2062753

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`')
Answered By: Sephel
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.