Skip to main content

How to Work with collections.OrderedDict (Get First/Last, Indexing, Merging) in Python

While standard Python dictionaries (dict) preserve insertion order as of Python 3.7+, the collections.OrderedDict class was the primary way to guarantee order in earlier Python versions and still offers some specific behaviors (like equality comparison considering order). Working with ordered dictionaries sometimes requires accessing elements based on their insertion position (like the first or last item) or finding the numerical index of a key.

This guide demonstrates common operations on OrderedDict objects, including getting the first/last elements, accessing items by index, merging, finding indices, and converting to standard types.

Understanding OrderedDict (and dict Order)

collections.OrderedDict is a dictionary subclass that remembers the order in which keys were first inserted. If a new entry overwrites an existing entry, the original insertion position is left unchanged. Deleting and reinserting an entry moves it to the end.

note

Since Python 3.7, standard dict objects also preserve insertion order as a language feature. For many use cases relying purely on insertion order, a standard dict is now sufficient and often preferred for simplicity. OrderedDict remains useful if you need order-sensitive equality checks or compatibility with older Python versions (< 3.7).

# Setup for examples
from collections import OrderedDict

od = OrderedDict()
od['apple'] = 1
od['banana'] = 2
od['cherry'] = 3

# Current order: apple, banana, cherry
print(f"Initial OrderedDict: {od}")

Getting the First Element (Key, Value, Item)

Since OrderedDict maintains insertion order, you can reliably get the first added item.

Using next() and iter()

The most direct way is to get an iterator from the dictionary (which yields keys by default) or its views (.values(), .items()) and fetch the first item using next().

from collections import OrderedDict

my_od = OrderedDict(
[('first', 'Apple'), ('second', 'Banana'), ('third', 'Cherry')]
)

if my_od: # Check if not empty before using next() without default
# ✅ Get the first KEY
first_key = next(iter(my_od))
print(f"First Key: '{first_key}'") # Output: First Key: 'first'

# ✅ Get the first VALUE (using the key)
first_value = my_od[first_key]
print(f"First Value: '{first_value}'") # Output: First Value: 'Apple'

# ✅ Get the first ITEM (key-value tuple)
first_item_pair = next(iter(my_od.items()))
print(f"First Item (Key, Value): {first_item_pair}") # Output: First Item (Key, Value): ('first', 'Apple')
else:
print("OrderedDict is empty.")

Output:

First Key: 'first'
First Value: 'Apple'
First Item (Key, Value): ('first', 'Apple')
  • iter(my_od): Creates an iterator over the keys of the OrderedDict in insertion order.
  • iter(my_od.items()): Creates an iterator over the (key, value) pairs in insertion order.
  • next(iterator): Retrieves the next (in this case, the first) item from the iterator.

Handling Empty Dictionaries

Calling next() on an iterator obtained from an empty OrderedDict will raise a StopIteration error. To handle this gracefully, provide a default value to next().

from collections import OrderedDict

empty_od = OrderedDict()

# Provide a default value (e.g., None) if the dict might be empty
first_key = next(iter(empty_od), None)
first_item = next(iter(empty_od.items()), None)

print(f"First key (empty): {first_key}") # Output: First key (empty): None
print(f"First item (empty): {first_item}") # Output: First item (empty): None

Getting the Last Element (Key, Value, Item)

Using next() and reversed()

Combine reversed() with next() to get the last inserted item efficiently.

from collections import OrderedDict

my_od = OrderedDict(
[('first', 'Apple'), ('second', 'Banana'), ('third', 'Cherry')]
)

if my_od:
# ✅ Get the last KEY
last_key = next(reversed(my_od))
print(f"Last Key: '{last_key}'") # Output: Last Key: 'third'

# ✅ Get the last VALUE (using the key)
last_value = my_od[last_key]
print(f"Last Value: '{last_value}'") # Output: Last Value: 'Cherry'

# ✅ Get the last ITEM (key-value tuple)
last_item_pair = next(reversed(my_od.items()))
print(f"Last Item (Key, Value): {last_item_pair}") # Output: Last Item (Key, Value): ('third', 'Cherry')
else:
print("OrderedDict is empty.")

Output:

Last Key: 'third'
Last Value: 'Cherry'
Last Item (Key, Value): ('third', 'Cherry')
  • reversed(my_od): Creates a reverse iterator over the keys.
  • reversed(my_od.items()): Creates a reverse iterator over the items.
  • next(...): Gets the first item from the reversed iterator, which corresponds to the last item in the original OrderedDict.

Handling Empty Dictionaries

Use the default argument with next() for empty dictionaries, just like when getting the first element.

from collections import OrderedDict

empty_od = OrderedDict()

last_key = next(reversed(empty_od), None)
last_item = next(reversed(empty_od.items()), None)

print(f"Last key (empty): {last_key}") # Output: Last key (empty): None
print(f"Last item (empty): {last_item}") # Output: Last item (empty): None

Output:

Last key (empty): None
Last item (empty): None

Accessing Items by Index (Positional Access)

OrderedDict objects themselves are not directly subscriptable by integer index (like my_od[0]). To access the Nth item based on insertion order, you must first convert a view (.keys(), .values(), or .items()) into a list.

Converting to List First

from collections import OrderedDict

my_od = OrderedDict(
[('apple', 1), ('banana', 2), ('cherry', 3), ('date', 4)]
)

# ✅ Convert items view to a list
items_list = list(my_od.items())
print(f"Items as list: {items_list}")
# Output: Items as list: [('apple', 1), ('banana', 2), ('cherry', 3), ('date', 4)]

# ✅ Access Nth item (e.g., second item, index 1)
try:
second_item = items_list[1] # Index 1 corresponds to the second item inserted
print(f"Second item (index 1): {second_item}") # Output: Second item (index 1): ('banana', 2)

# Access key/value of the Nth item
second_key = second_item[0]
second_value = second_item[1]
print(f" Key: {second_key}, Value: {second_value}") # Output: Key: banana, Value: 2

# Access last item (index -1)
last_item = items_list[-1]
print(f"Last item (index -1): {last_item}") # Output: Last item (index -1): ('date', 4)

except IndexError:
print("Index out of range for the items list.")

Output:

Items as list: [('apple', 1), ('banana', 2), ('cherry', 3), ('date', 4)]
Second item (index 1): ('banana', 2)
Key: banana, Value: 2
Last item (index -1): ('date', 4)
  • list(my_od.items()): Creates a list of (key, value) tuples in insertion order.
  • You can then use standard list indexing ([index]) on this list.

Accessing Keys/Values by Index

Similarly, convert .keys() or .values() to a list first.

from collections import OrderedDict

my_od = OrderedDict(
[('apple', 1), ('banana', 2), ('cherry', 3), ('date', 4)]
)

# ✅ Access Nth key
keys_list = list(my_od.keys())
print(f"Keys list: {keys_list}") # Output: Keys list: ['apple', 'banana', 'cherry', 'date']
print(f"Third key (index 2): '{keys_list[2]}'") # Output: Third key (index 2): 'cherry'

# ✅ Access Nth value
values_list = list(my_od.values())
print(f"Values list: {values_list}") # Output: Values list: [1, 2, 3, 4]
print(f"First value (index 0): {values_list[0]}") # Output: First value (index 0): 1

Output:

Keys list: ['apple', 'banana', 'cherry', 'date']
Third key (index 2): 'cherry'
Values list: [1, 2, 3, 4]
First value (index 0): 1

Getting All Keys/Values/Items as a List

As shown above, simply use list() on the corresponding view object:

  • list(my_od.keys())
  • list(my_od.values())
  • list(my_od.items())

Getting the Index of a Key or Value

To find the numerical index (based on insertion order) of a known key or value:

Finding Index of a Key

Convert keys to a list and use list.index().

from collections import OrderedDict

my_od = OrderedDict(
[('apple', 1), ('banana', 2), ('cherry', 3)]
)

keys_list = list(my_od.keys()) # ['apple', 'banana', 'cherry']

try:
# ✅ Find index of key 'cherry'
index_of_cherry = keys_list.index('cherry')
print(f"Index of key 'cherry': {index_of_cherry}") # Output: Index of key 'cherry': 2
except ValueError:
print("Key not found.")

Finding Index of a Value

Convert values to a list and use list.index(). Note this finds the index of the first occurrence if the value is duplicated.

from collections import OrderedDict

my_od = OrderedDict(
[('apple', 10), ('banana', 20), ('cherry', 30), ('date', 20)]
)

values_list = list(my_od.values()) # [10, 20, 30, 20]

try:
# ✅ Find index of value 20 (finds first occurrence)
index_of_20 = values_list.index(20)
print(f"Index of first value 20: {index_of_20}") # Output: Index of first value 20: 1
except ValueError:
print("Value not found.")
  • list.index() raises a ValueError if the item is not found. Use try...except or an if value in values_list: check first.

Merging Two OrderedDict Objects

Creating a New Merged OrderedDict

Concatenate the .items() lists from both dictionaries and pass the result to the OrderedDict constructor. This preserves the order from the first dict, followed by the order from the second. Keys from the second dict will overwrite keys from the first if they conflict.

from collections import OrderedDict

od1 = OrderedDict([('a', 1), ('b', 2)])
od2 = OrderedDict([('b', 20), ('c', 3), ('d', 4)]) # 'b' will overwrite

# ✅ Merge by concatenating item lists
merged_items = list(od1.items()) + list(od2.items())
merged_od = OrderedDict(merged_items)

print(f"OD1: {od1}") # Output: OD1: OrderedDict({'a': 1, 'b': 2})
print(f"OD2: {od2}") # Output: OD2: OrderedDict({'b': 20, 'c': 3, 'd': 4})
print(f"Merged OD: {merged_od}") # Output: Merged OD: OrderedDict({'a': 1, 'b': 20, 'c': 3, 'd': 4})

Updating an OrderedDict In-Place

Use the standard update() method. This modifies the first OrderedDict directly. New keys from the second dict are appended to the end. Existing keys are updated in place, retaining their original position.

from collections import OrderedDict

od1 = OrderedDict([('a', 1), ('b', 2), ('e', 5)])
od2 = OrderedDict([('c', 3), ('b', 20), ('d', 4)]) # 'b' exists, 'c','d' are new

print(f"OD1 before update: {od1}")

# ✅ Update od1 in-place
od1.update(od2)

print(f"OD1 after update: {od1}")
# Output: OD1 after update: OrderedDict([('a', 1), ('b', 20), ('e', 5), ('c', 3), ('d', 4)])
note

'b' was updated, 'c' and 'd' were added at the end.

Converting OrderedDict to dict or list

  • To dict: Simply pass the OrderedDict to the dict() constructor. The order is preserved if using Python 3.7+.
    from collections import OrderedDict
    my_od = OrderedDict([('b', 2), ('a', 1)])
    regular_dict = dict(my_od)
    print(f"Converted to dict: {regular_dict}") # Output: {'b': 2, 'a': 1}
    print(f"Type: {type(regular_dict)}") # Output: <class 'dict'>
  • To list: Convert the desired view (.keys(), .values(), .items()) using list().
    from collections import OrderedDict
    my_od = OrderedDict([('b', 2), ('a', 1)])
    items_list = list(my_od.items())
    print(f"Converted to list of items: {items_list}") # Output: [('b', 2), ('a', 1)]

Conclusion

While standard Python dictionaries now preserve insertion order (since 3.7), collections.OrderedDict offers explicit order guarantees and compatibility. Key operations include:

  • Getting the first/last elements using next(iter(od)) or next(reversed(od)).
  • Accessing by index requires converting .keys(), .values(), or .items() to a list first.
  • Finding the index of a key/value also requires converting the appropriate view to a list and using list.index().
  • Merging can be done by concatenating .items() lists into a new OrderedDict or using .update() to modify in-place.
  • Converting to dict or list is straightforward using the respective constructors.

Remember the standard dict capabilities in modern Python, but use OrderedDict when explicit order or pre-3.7 compatibility is required.