I have two dictionaries.I'm iterating over it one inside the other. I want to select the next item each time it iterates inside the inner loop rather than from the beginning.
dict1={'a':1 , 'b':2 , 'c':3}
dict2={'x':10, 'y':20, 'z':30}
for key,value in dict1:
#do something
for k,v in dict2:
#do something
When key='a', it iterates over inner loop and does some action according to the code in that loop.Suppose that it action that it selected was 'x' in dict2. Now when I have to iterate with key='b', I want the iteration for the inner loop to start from 'y' because 'x' was already selected.
First, for key,value in dict1
doesn't do what you want—it just iterates over the keys. If you want to iterate over key-value pair, you need for key, value in dict1.items()
.
Meanwhile, it sounds like what you're asking for is lock-step iteration, not nested iteration? If so, you want the zip
function:
for (k1, v1), (k2, v2) in zip(dict1.items(), dict2.items()):
# do something
But note that the ordering this gives you will actually be arbitrary, because the ordering of dicts is inherently arbitrary. So, if you're happy with ('a', 'x')
, then ('b', 'y')
, etc., and also happy with ('a', 'y')
, then ('b', 'x')
, then zip
is what you want. If not, it isn't.
(If you expected your dict
s to have some inherent order, such as order of insertion, or sorted order, or anything else, you will have to use a different class. For example, collections.OrderedDict
acts like a dictionary, but maintains the insertion order.)
If you want something more complicated, where you move the iteration over dict2
programmatically in a way you can't express in a one-liner, you can always use the iteration protocol manually:
iter2 = iter(dict2.items())
for k1, v1 in dict1.items():
k2, v2 = next(iter2)
# do something
# maybe do another k2, v2 = next(iter2)
# maybe restart iter2 = iter(dict2.items())
# and so on
As the docs explain, when next(iter2)
gets to the end, it will raise StopIteration
. What if you don't want that? Maybe you want to, as you suggested in a comment, start over again? You can solve that by catching StopIteration
, or by using the two-argument form of next
and checking for a sentinel. For example:
try:
k2, v2 = next(iter2)
except StopIteration:
iter2 = iter(dict2.items())
k2, v2 = next(iter2)
Or you can even write a circular iteration wrapper:
def circular_iterate(iterable_factory):
while True:
yield from iterable_factory():
In Python 3.2 or earlier, you have to replace the yield from
with an inner loop:
def circular_iterate(iterable_factory):
while True:
for value in iterable_factory():
yield value
And now:
iter2 = circular_iterate(dict2.items) # note, not dict2.items()
If you're trying to track more than just a "current position", you probably need an additional data structure. For example, if you want to skip over all keys seen so far, use a set
of keys seen so far, or a set
of keys not seen:
seen_items_2 = set()
for k1, v1 in dict1.items():
for k2, v2 in dict2.items():
if k2 in seen_items_2:
continue
seen_items_2.add(k2)
# do something
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With