patternpythonMinor
Finding previous/next item in an OrderedDict
Viewed 0 times
itempreviousordereddictnextfinding
Problem
I have an OrderedDict and, given a key in it, need to find the previous and next keys accordingly. The implementation should wrap (i.e. if the given key is the first in the dictionary, the previous key should be the last one and vice versa).
Here's what I've come up with so far (adapted from production code) which works, but seems a bit... clunky. Any tips for improvement would be appreciated!
Here's what I've come up with so far (adapted from production code) which works, but seems a bit... clunky. Any tips for improvement would be appreciated!
from collections import OrderedDict
# Create a sample
a_dict = OrderedDict()
for n in range(25):
a_dict.update({n: n + 1})
# The currently-selected key (not a plain int in my actual production code)
selected = 0
the_keys = list(a_dict.keys())
# Only find the prev/next item if we have more than one key
if len(the_keys) <= 1:
return
current = None
for index, key in enumerate(the_keys):
if key == selected:
current = index
break
# For the majority of cases
prev = current - 1
next = current + 1
# For the edge cases (ends of the list)
if current == 0:
prev = -1
next = 1
elif current == len(the_keys) - 1:
prev = current - 1
next = 0Solution
One way of simplifying the problem is to provide a thin wrapper around the
An other way is to make use of
You then just have to populate your dictionary and freeze it into this wrapper.
If you need to be able to modify the dictionary contained in
OrderedDict. Something along the lines of:class DictCycler:
def __init__(self, data):
self.data = data
...
def next(self):
...
def previous(self):
...An other way is to make use of
itertools capability. Especially cycle and islice. The idea being that, using cycle, cycling through the elements in the proper order is straightforward, and cycling in reverse can be done by going forward N - 2 times (where N is the length of the dictionary) with the help of islice. This yield:import itertools
class DictCycler:
def __init__(self, data):
self.data = data
self.iterator = itertools.cycle(data)
self.jump_to_previous = len(data) - 2
def next(self):
return self.data[next(self.iterator)]
def previous(self):
prev = itertools.islice(self.iterator, self.jump_to_previous, None)
return self.data[next(prev)]You then just have to populate your dictionary and freeze it into this wrapper.
If you need to be able to modify the dictionary contained in
data after passing it to this class, you will need to adapt the recipe a bit.Code Snippets
class DictCycler:
def __init__(self, data):
self.data = data
...
def next(self):
...
def previous(self):
...import itertools
class DictCycler:
def __init__(self, data):
self.data = data
self.iterator = itertools.cycle(data)
self.jump_to_previous = len(data) - 2
def next(self):
return self.data[next(self.iterator)]
def previous(self):
prev = itertools.islice(self.iterator, self.jump_to_previous, None)
return self.data[next(prev)]Context
StackExchange Code Review Q#156982, answer score: 3
Revisions (0)
No revisions yet.