11

I'm trying to print the key and value using the below code :

data = {"Key1" : "Value1", "Key2" : "Value2"}
print(data.keys()[1])   
print(data.values()[1])

I get the error

'dict_keys' object does not support indexing

What is wrong with the mentioned code?

Accepted Output :

Key2
Value2
  • [dict.keys()\[0\] on Python 3](https://stackoverflow.com/q/18686903/2301450) – vaultah Aug 23 '17 at 09:51
  • It’s not a good idea to rely on `dict` ordering. Use [an `OrderedDict`](https://docs.python.org/3/library/collections.html#collections.OrderedDict) instead. – Ry- Aug 23 '17 at 09:54
  • 'dict_keys' object does not support indexing –  Aug 23 '17 at 09:54
  • Possible duplicate of [Access an arbitrary element in a dictionary in Python](https://stackoverflow.com/questions/3097866/access-an-arbitrary-element-in-a-dictionary-in-python) – Chris_Rands Aug 23 '17 at 10:01
  • Well the dupe I suggested is value not key, perhaps https://stackoverflow.com/questions/30362391/how-to-find-first-key-in-a-dictionary – Chris_Rands Aug 23 '17 at 10:03

7 Answers7

16

Shortest:

mydict = {"Key1" : "Value1", "Key2" : "Value2"}
print( next(iter(mydict)) ) # 'Key1'

For both the key and value:

print( next(iter( mydict.items() )) ) # ('Key1', 'Value1')
cssyphus
  • 37,875
  • 18
  • 96
  • 111
14

in python3 data.keys() returns a dict_keys object, so, in general, apply list on it to be able to index/slice it:

data = {"Key1" : "Value1", "Key2" : "Value2"}
print(data.keys()) 
# output >>> dict_keys(['Key1', 'Key2'])
print(list(data.keys())[1])   
# output >>> Key2
print(list(data.values())[1])
# output >>> Value2

For your specific case, you need to convert the dictionary to an ordered one to conserve the order and get the first element as follows:

from collections import OrderedDict 
data = {"Key1" : "Value1", "Key2" : "Value2"}
data = OrderedDict(data)
print(data)
# output >>> OrderedDict([('Key1', 'Value1'), ('Key2', 'Value2')])
print(list(data.keys())[0])
# output >>> Key1

Edit:

Based on comments from @Mseifert (thanks), preserving the order after conversion from the unordered dictionary to the ordered one is only an implementation detail that works in python3.6 and we cannot rely on, here's the discussion Mseifert shared:

So the correct way to do what you want is to explicitly define the order

from collections import OrderedDict
data = OrderedDict([('Key1', 'Value1'), ('Key2', 'Value2')])
print(list(data.keys())[0])
Mohamed Ali JAMAOUI
  • 14,275
  • 14
  • 73
  • 117
  • 1
    The code of this answer is correct but that’s misleading; dict keys aren’t ordered so calling `list(data.keys())[0]` won’t return the "first" key of the dict because there’s no such thing as a "first key" in a dict. – bfontaine Aug 23 '17 at 10:01
  • @bfontaine edited according to the specific request of the OP. – Mohamed Ali JAMAOUI Aug 23 '17 at 10:08
  • 1
    I haven't downvoted *but* when you do `data = {"Key1" : "Value1", "Key2" : "Value2"}` the order is gone, there's no point converting it to an `OrderedDict(data)` afterwards. – MSeifert Aug 23 '17 at 10:08
  • I've tested it on python3.6, the order is preserved, please check here: https://repl.it/KVt8. @MSeifert can you point me to the doc link stating otherwise? – Mohamed Ali JAMAOUI Aug 23 '17 at 10:11
  • Even though it works in 3.6 (it won't in earlier versions and the question isn't explicitly tagged for Python 3.6) that's an implementation detail you shouldn't rely on (see also https://stackoverflow.com/questions/39980323/dictionaries-are-ordered-in-python-3-6) – MSeifert Aug 23 '17 at 10:14
  • @MSeifert thanks for sharing, that's cool, I learnt something new :) – Mohamed Ali JAMAOUI Aug 23 '17 at 10:20
3

Dictionaries are unordered and in the newer Python versions the hashes of strings are randomized (per session). So you have to accept that what you get as "n"-th key (or value) of a dictionary isn't predictable (at least when the keys are strings).

But if you just want the element that happens to be "first" (or "second") just use list to convert the dict_keys to an sequence that can be indexed:

print(list(data.keys())[1])   
print(list(data.values())[1])

However, my suggestion would be to use an OrderedDict instead of a normal dict to make the result deterministic:

from collections import OrderedDict
data = OrderedDict([("Key1", "Value1"), ("Key2", "Value2")])
print(list(data.keys())[1])     # Key2
print(list(data.values())[1])   # Value2
MSeifert
  • 145,886
  • 38
  • 333
  • 352
1

In Python, dicts are unordered data structures. Therefore there is no first key. If you want to have a dict-like data structure with internal ordering of keys, have a look at OrderedDict.

Richard Neumann
  • 2,986
  • 2
  • 25
  • 50
1

It does rather depend on what you mean by first. In Python 3.6, entries in a dictionary are ordered by the key, but probably not quite in the way you expect.

To take your example:

>>> data = {"Key1" : "Value1", "Key2" : "Value2"}

Now add the key 0:

>>> data[0] = "Value0"
>>> data
{'Key1': 'Value1', 'Key2': 'Value2', 0: 'Value0'}

So the zero comes at the end. But if you construct the dict from scratch, like this:

>>> data = {0: "Value0", "Key1" : "Value1", "Key2" : "Value2"}

you get this result instead

>>> data
{0: 'Value0', 'Key1': 'Value1', 'Key2': 'Value2'}

This illustrates the principle that you should not depend on the ordering, which is defined only by the dict implementation, which, in CPython 3.6 and later, is order of entry. To illustrate that point in a different way:

>>> data = {0: "Value0", "Key1" : "Value1", "Key2" : "Value2"}
>>> sorted(data.keys())
Traceback (most recent call last):
  File "<pyshell#42>", line 1, in <module>
    sorted(data.keys())
TypeError: '<' not supported between instances of 'str' and 'int'

Guido has this to say on the subject:

I'd like to handwave on the ordering of ... dicts. Yes, in CPython 3.6 and in PyPy they are all ordered, but it's an implementation detail. I don't want to force all other implementations to follow suit. I also don't want too many people start depending on this, since their code will break in 3.5. (Code that needs to depend on the ordering of keyword args or class attributes should be relatively uncommon; but people will start to depend on the ordering of all dicts all too easily. I want to remind them that they are taking a risk, and their code won't be backwards compatible.)

The full post is here.

BoarGules
  • 16,440
  • 2
  • 27
  • 44
1

For Python 3 you can simply do

first_key = next(iter(data.keys()))
print(first_key)   # 'Key1'
dtar
  • 1,469
  • 12
  • 17
0

Dicts represent an unordered datatype, therefore there is no indexing. There is an option in collections. Try OrderedDict.

import collections

d = collections.OrderedDict()
d['Key1'] = 'Value1'
d['Key2'] = 'Value2' # that's how to add values to OrderedDict

items = list(d.items())
print(items)
#[('Key1', 'Value1'), ('Key2', 'Value2')]
print(items[0])
#('Key1', 'Value1')
print(items[1])
#('Key2', 'Value2')
techkuz
  • 3,608
  • 5
  • 34
  • 62