Shortest way to get first item of `OrderedDict` in Python 3
Asked Answered
L

7

80

What's the shortest way to get first item of OrderedDict in Python 3?

My best:

list(ordered_dict.items())[0]

Quite long and ugly.

I can think of:

next(iter(ordered_dict.items()))       # Fixed, thanks Ashwini

But it's not very self-describing.

Any better suggestions?

Lobation answered 11/1, 2014 at 13:25 Comment(6)
using list is a bad idea. the entire list will be populate before you'll get the first item. Using next() is optimal because .items() return an iterator and will yield only one value.Perdition
What do you mean by shortest way? lesser number of characters?Yokum
I think you'll need an iter call too: next(iter(d.items())) as .items returns a View object.Plumber
@Yokum yes, less characters, but hopefully idiomatic too.Lobation
I was wondering if next(iter(ordered_dict.items())) this will advance the iterator or not. As expected it does not advance the iterator! Also is it safe to assume that next(iter(ordered_dict.items())) runs in O(1) time?Laboy
next(iter(self.items())) will give you the first pair (key, val)Premillenarian
G
76

Programming Practices for Readabililty

In general, if you feel like code is not self-describing, the usual solution is to factor it out into a well-named function:

def first(s):
    '''Return the first element from an ordered collection
       or an arbitrary element from an unordered collection.
       Raise StopIteration if the collection is empty.
    '''
    return next(iter(s))

With that helper function, the subsequent code becomes very readable:

>>> extension = {'xml', 'html', 'css', 'php', 'xhmtl'}
>>> one_extension = first(extension)

Patterns for Extracting a Single Value from Collection

The usual ways to get an element from a set, dict, OrderedDict, generator, or other non-indexable collection are:

for value in some_collection:
    break

and:

value = next(iter(some_collection))

The latter is nice because the next() function lets you specify a default value if collection is empty or you can choose to let it raise an exception. The next() function is also explicit that it is asking for the next item.

Alternative Approach

If you actually need indexing and slicing and other sequence behaviors (such as indexing multiple elements), it is a simple matter to convert to a list with list(some_collection) or to use [itertools.islice()][2]:

s = list(some_collection)
print(s[0], s[1])

s = list(islice(n, some_collection))
print(s)
Googolplex answered 11/1, 2014 at 21:4 Comment(4)
I like the latter option, but in your opinion is it better than list(ordered_dict.items())[0]? If anything I think the [0] is more obvious.Ladida
@bedeabc list(ordered_dict.items())[0] goes ahead to create a list of all items in the dict, then takes the first item of that list, then throws away that list. You certainly don't want to do that.Latonya
@Latonya I understand, and have become comfortable with the next(iter()) pattern, but for trivially small data structures I don't see the issue with prioritising readability.Ladida
next(iter(self.items())) will give you the first pair (key, val)Premillenarian
C
32

Use popitem(last=False), but keep in mind that it removes the entry from the dictionary, i.e. is destructive.

from collections import OrderedDict
o = OrderedDict()
o['first'] = 123
o['second'] = 234
o['third'] = 345

first_item = o.popitem(last=False)
>>> ('first', 123)

For more details, have a look at the manual on collections. It also works with Python 2.x.

Casque answered 27/12, 2014 at 11:17 Comment(3)
This is the best way for me, in case you don' t bother to destroy the dictionaryBandsman
I want a non-destructive approach. How do I do it?Premillenarian
something besides: next(iter(self.items())) which gives (key, val)Premillenarian
S
5

Subclassing and adding a method to OrderedDict would be the answer to clarity issues:

>>> o = ExtOrderedDict(('a',1), ('b', 2))
>>> o.first_item()
('a', 1)

The implementation of ExtOrderedDict:

class ExtOrderedDict(OrderedDict):
    def first_item(self):
        return next(iter(self.items()))
Sainthood answered 28/8, 2016 at 20:43 Comment(1)
is there not something without creating an iteratior? like an api from OD?Premillenarian
B
5

Code that's readable, leaves the OrderedDict unchanged and doesn't needlessly generate a potentially large list just to get the first item:

for item in ordered_dict.items():
    return item

If ordered_dict is empty, None would be returned implicitly.

An alternate version for use inside a stretch of code:

for first in ordered_dict.items():
    break  # Leave the name 'first' bound to the first item
else:
    raise IndexError("Empty ordered dict")

The Python 2.x code corresponding to the first example above would need to use iteritems() instead:

for item in ordered_dict.iteritems():
    return item
Billmyre answered 13/12, 2018 at 12:22 Comment(1)
next(iter(self.items())) will give you the first pair (key, val)Premillenarian
C
1

You might want to consider using SortedDict instead of OrderedDict.

It provides SortedDict.peekitem to peek an item.

Runtime complexity: O(log(n))

>>> sd = SortedDict({'a': 1, 'b': 2, 'c': 3})
>>> sd.peekitem(0)
('a', 1)
Castoff answered 21/11, 2022 at 9:20 Comment(0)
L
0

If you need a one-liner:

ordered_dict[[*ordered_dict.keys()][0]]

It creates a list of dict keys, picks the first and use it as key to access the dictionary value.

Lyricism answered 25/1, 2023 at 13:29 Comment(1)
Need an O(1) solutionWilber
V
-2

First record:

[key for key, value in ordered_dict][0]

Last record:

[key for key, value in ordered_dict][-1]
Vera answered 1/2, 2019 at 19:31 Comment(4)
Hi, thank you for your contribution to StackOverflow! While this works and is straightforward to understand, this is a very inefficient way to do it, as the whole list will have to be created in memory, before the single element you want can be extracted.Chemulpo
Welcome to StackOverflow @galaga4! Can you help me here - Looks like this is will create a List which is not needed!Laboy
The fact that it is inefficient does not make it wrong. It's a perfectly fine solution and may be an easy way to get what OP wants for short lists.Pazit
next(iter(self.items())) will give you the first pair (key, val)Premillenarian

© 2022 - 2024 — McMap. All rights reserved.