21

I have a snippet of code which orders a dictionary alphabetically. Is there a way to select the ith key in the ordered dictionary and return its corresponding value? i.e.

import collections
initial = dict(a=1, b=2, c=2, d=1, e=3)
ordered_dict = collections.OrderedDict(sorted(initial.items(), key=lambda t: t[0]))
print(ordered_dict)
OrderedDict([('a', 1), ('b', 2), ('c', 2), ('d', 1), ('e', 3)])

I want to have some function along the vein of...

select = int(input("Input dictionary index"))
#User inputs 2
#Program looks up the 2nd entry in ordered_dict (c in this case)
#And then returns the value of c (2 in this case)

How can this be achieved? Thanks.

(Similar to Accessing Items In a ordereddict, but I only want to output the value of the key-value pair.)

asked Mar 24, 2014 at 13:32
5
  • try ordered_dict[ordered_dict.keys()[index]] Commented Mar 24, 2014 at 13:34
  • @IonutHulub, I tried (without the user input bit) print(ordered_dict[ordered_dict.keys()[2]]) and received the error, TypeError: "KeysView" object does not support indexing. Commented Mar 24, 2014 at 13:40
  • lambda is written with b before the d. Commented Mar 24, 2014 at 13:40
  • @DanielLee My apologies, corrected. Commented Mar 24, 2014 at 13:41
  • you could avoid sorting the whole initial dictionary if input is a small index by using heapq: result = initial[heapq.nsmallest(select+1, initial)[-1]] Commented Mar 24, 2014 at 13:50

5 Answers 5

26

In Python 2:

If you want to access the key:

>>> ordered_dict = OrderedDict([('a', 1), ('b', 2), ('c', 2), ('d', 1), ('e', 3)])
>>> ordered_dict.keys()[2]
'c'

If want to access the value:

>>> ordered_dict.values()[2]
2

If you're using Python 3, you can convert the KeysView object returned by the keys method by wrapping it as a list:

>>> list(ordered_dict.keys())[2]
'c'
>>> list(ordered_dict.values())[2]
2

Not the prettiest solution, but it works.

Daniel Holmes
2,0222 gold badges19 silver badges30 bronze badges
answered Mar 24, 2014 at 13:39
Sign up to request clarification or add additional context in comments.

Comments

12

Using itertools.islice is efficient here, because we don't have to create any intermediate lists, for the sake of subscripting.

from itertools import islice
print(next(islice(ordered_dict.items(), 2, None)))

If you want just the value, you can do

print ordered_dict[next(islice(ordered_dict, 2, None))]
answered Mar 24, 2014 at 13:35

6 Comments

Ahh, not quite what I want. Your method returns the key-value pair, but I only want the code to return the value of the key
+1. islice is preferable but for a small dictionary list(ordered_dict.values())[2] might be faster i.e., don't assume what is faster until you've measured it
@JFSebastian, Interesting, what makes islice preferable for small dictionaries? Just the logic behind the code or something else?
@Pingk He says, islice is preferable but not for small dicts
Sorry, I read it wrong, but what makes it faster/slower compared to list? @thefourtheye
|
6

Do you have to use an OrderedDict or do you just want a dict-like type that supports indexing? If the latter, then consider a sorted dict object. Some implementations of SortedDict (which orders pairs based on the key sort order) support fast n-th indexing. For example, the sortedcontainers project has a SortedDict type with random-access indexing.

In your case it would look something like:

>>> from sortedcontainers import SortedDict
>>> sorted_dict = SortedDict(a=1, b=2, c=2, d=1, e=3)
>>> print sorted_dict.iloc[2]
'c'

If you do a lot of lookups, this will be a lot faster than repeatedly iterating to the desired index.

answered Apr 8, 2014 at 4:22

3 Comments

Thanks very much, and I may use this in the future, but the method I've logged as the correct answer does a very similar method to this. I'm curious though, will the dictionary stay ordered if I change the value of one of the k-v pairs, or will it re-arrange itself like the standard dictionary?
Yes, it will automatically stay sorted by the keys. It'll be much faster than the accepted solution if your making edits to the dictionary and then indexing.
Awesome, I'll probably use this next time then. I don't think I'll change the accepted answer, but I'll vote you up.
1

You could do something along these lines (od is the ordered dict):

def get_idx(od, idx):
 from itertools import islice
 idx = (idx + len(od)) % len(od)
 t = islice(od.items(), idx, idx + 1)
 return next(t)
>>>x
OrderedDict([('a', 2), ('b', 3), ('k', 23), ('t', 41), ('q', 23)])
>>>get_idx(x, 1)
('b', 3)
>>>get_idx(x, 2)
('k', 23)
>>>get_idx(x, 4)
('q', 23)
>>>get_idx(x, -1)
('q', 23)
>>>get_idx(x, -2)
('t', 41)
answered Mar 17, 2019 at 3:29

Comments

0

Don't underestimate just a plain 'ole for loop:

from collections import OrderedDict
od=OrderedDict([('a', 1), ('b', 2), ('c', 2), ('d', 1), ('e', 3)])
def ith(od, tgt):
 for i, t in enumerate(od.items()):
 if i==tgt:
 print('element {}\'s key is "{}"'.format(i,t[0]))
 break
 else:
 print('element {} not found'.format(tgt)) 
ith(od, 2)
# element 2's key is "c"
ith(od, 20) 
# element 20 not found

The advantage here is that the loop will break as soon as the desired element is found and returns a sensible result if not found...

The disadvantage is that relative slices are not supported.

answered Mar 24, 2014 at 15:13

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.