diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -152,6 +152,38 @@ class OrderedDict(dict): link.next = first root.next = first.prev = link + def rotate_at(self, key): + '''Rotate the ordered dict so that the existing element is at the + beginning. + ''' + link = self.__map[key] + root = self.__root + if root.next is not link: + # Remove the root from where it is + root.next.prev = root.prev + root.prev.next = root.next + # and transplant it where desired + last = link.prev + root.prev = last + root.next = link + last.next = link.prev = root + + def rotate_after(self, key): + '''Rotate the ordered dict so that the existing element is at the + end. + ''' + link = self.__map[key] + root = self.__root + if root.prev is not link: + # Remove the root from where it is + root.next.prev = root.prev + root.prev.next = root.next + # and transplant it where desired + first = link.next + root.prev = link + root.next = first + link.next = first.prev = root + def __sizeof__(self): sizeof = _sys.getsizeof n = len(self) + 1 # number of links including root diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -1304,6 +1304,40 @@ class TestOrderedDict(unittest.TestCase) with self.assertRaises(KeyError): od.move_to_end('x') + def test_rotate_at(self): + od = OrderedDict.fromkeys('abcde') + self.assertEqual(list(od), list('abcde')) + od.rotate_at('c') + self.assertEqual(list(od), list('cdeab')) + od.rotate_at('c') + self.assertEqual(list(od), list('cdeab')) + od.rotate_at('b') + self.assertEqual(list(od), list('bcdea')) + od.rotate_at('a') + self.assertEqual(list(od), list('abcde')) + od.rotate_at('b') + self.assertEqual(list(od), list('bcdea')) + od.rotate_at('c') + self.assertEqual(list(od), list('cdeab')) + self.assertRaises(KeyError, od.rotate_at, 'z') + + def test_rotate_after(self): + od = OrderedDict.fromkeys('abcde') + self.assertEqual(list(od), list('abcde')) + od.rotate_after('c') + self.assertEqual(list(od), list('deabc')) + od.rotate_after('c') + self.assertEqual(list(od), list('deabc')) + od.rotate_after('d') + self.assertEqual(list(od), list('eabcd')) + od.rotate_after('e') + self.assertEqual(list(od), list('abcde')) + od.rotate_after('d') + self.assertEqual(list(od), list('eabcd')) + od.rotate_after('c') + self.assertEqual(list(od), list('deabc')) + self.assertRaises(KeyError, od.rotate_after, 'z') + def test_sizeof(self): # Wimpy test: Just verify the reported size is larger than a regular dict d = dict(a=1)