The Python Oracle

Start a dictionary for loop at a specific key value

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Future Grid Looping

--

Chapters
00:00 Start A Dictionary For Loop At A Specific Key Value
01:47 Answer 1 Score 0
02:10 Answer 2 Score 1
02:31 Answer 3 Score 1
03:35 Accepted Answer Score 2
04:26 Thank you

--

Full question
https://stackoverflow.com/questions/3110...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #performance #python27 #forloop #dictionary

#avk47



ACCEPTED ANSWER

Score 2


You may try to implement some caching mechanism within a custom subclass of dict.

You could set a self._cache = None in __init__, add a method like set_cache(self, key) to set the cache and finally overriding __iter__ to yield self._cache before calling the default __iter__.

However, that can be kinda cumbersome, if you consider this stackoverflow answer and also this one.

For what it's written in your question, I would try, instead, to implement this caching logic in your code.

def _match_region(self, name, position):
    rect = (self.regions["regions"][name]["pos1"], self.regions["regions"][name]["pos2"])
    return all(self.point_inside(rect, position))


if self.last_region and self._match_region(self.last_region, position):
    self.code_to_run_when_match(position)
    return

for name in self.regions["regions"]:
    if self._match_region(name, position):
        self.last_region = name
        self.code_to_run_when_match(position)
        return
return # if code gets here, the points were not inside any of the named regions



ANSWER 2

Score 1


That is right, dictionary is an unordered type. Therefore OrderedDict won't help you much for what you want to do.

You could store the last region into your class. Then, on the next call, check if last region is still good before check the entire dictionary ?




ANSWER 3

Score 1


Instead of a for-loop, you could use iterators directly. Here's an example function that does something similar to what you want, using iterators:

def iterate(what, iterator):
    iterator = iterator or what.iteritems()
    try:
        while True:
            k,v = iterator.next()
            print "Trying k = ", k
            if v > 100:
                return iterator
    except StopIteration:
        return None

Instead of storing the name of the region in last_region, you would store the result of this function, which is like a "pointer" to where you left off. Then, you can use the function like this (shown as if run in the Python interactive interpreter, including the output):

>>> x = {'a':12, 'b': 42, 'c':182, 'd': 9, 'e':12}
>>> last_region = None
>>> last_region = iterate(x, last_region)
Trying k = a
Trying k = c
>>> last_region = iterate(x, last_region)
Trying k = b
Trying k = e
Trying k = d

Thus, you can easily resume from where you left off, but there's one additional caveat to be aware of:

>>> last_region = iterate(x, last_region)
Trying k =  a
Trying k =  c
>>> x['z'] = 45
>>> last_region = iterate(x, last_region)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in iterate
RuntimeError: dictionary changed size during iteration

As you can see, it'll raise an error if you ever add a new key. So, if you use this method, you'll need to be sure to set last_region = None any time you add a new region to the dictionary.




ANSWER 4

Score 0


TigerhawkT3 is right. Dicts are unordered in a sense that there is no guaranteed order or keys in the given dictionary. You can even have different order of keys if you iterate over same dictionary. If you want order you need to use either OrderedDict or just plain list. You can convert your dict to list and sort it the way it represents the order you need.