222

In Python, given a dictionary like

{
    'VENEZUELA': 'CARACAS',
    'CANADA': 'OTTAWA'
}

How can I choose a random item (key-value pair)?

What if I only need the key, or only the value - can it be optimized?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
tekknolagi
  • 10,663
  • 24
  • 75
  • 119

18 Answers18

374

Make a list of the dictionary's items, and choose randomly from that in the usual way:

import random
d = {'VENEZUELA':'CARACAS', 'CANADA':'OTTAWA'}
country, capital = random.choice(list(d.items()))

Similarly, if only a value is needed, choose directly from the values:

capital = random.choice(list(d.values()))
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Gerrat
  • 28,863
  • 9
  • 73
  • 101
  • 1
    To expand on Duncan's comment, you can also just do `random.choice([d.keys()])`. The brackets convert the iterator to a list just the same as calling `list()`, but it may look a bit cleaner for some. – Seaux Jul 14 '15 at 15:48
  • 18
    Is this efficient? Does this scale if dict gets really large? –  Jul 25 '15 at 19:11
  • 1
    @code-法: Depends on what you mean by *efficient*, and *large*. A quick test shows it can pick a million random values out of a dictionary with a million entries in less than a second (assumes saving off the `d.keys()` part). Is that efficient? – Gerrat Aug 11 '15 at 20:44
  • @Gerrat, do you know if the transformation of d.keys() from iterator to list if constant (k) or O(n)? – toto_tico Sep 20 '15 at 15:11
  • 2
    @toto_tico: Changing an iterator to a list would be O(n) – Gerrat Sep 21 '15 at 15:30
  • 1
    @Seaux: brackets just make a one-item list whose item is the iterator itself. They don't make a list whose items are the iterator's items. – Bruno Le Floch Dec 07 '16 at 14:43
  • 1
    @austingae: because `random.choice` takes sequence as the parameter (see [Sequence Types](https://docs.python.org/library/stdtypes.html#sequence-types-list-tuple-range)) and dictionary isn't a sequence - you can't refer to its elements by index. – Jackenmen Feb 19 '19 at 23:40
  • Careful: this answer does not seem to apply for complex keys (tuples, lists, and possibly other iterables). In that case: `index = random.choice(range(len(d)))` and work from there (remember order is only garantueed in OrderedDict). – David. Jan 10 '20 at 14:23
  • @Seaux that does not work - it makes a list **of one item**, which is the entire keys-view. Did you mean `random.choice([*d.keys()])` (note the `*`)? – Karl Knechtel Mar 17 '23 at 06:08
  • @David. I have no idea what leads you to this conclusion. Lists can't be used as keys at all in the first place, and tuple keys work just fine with this code. Also, there is no reason why we should care about the key order when *the goal is to choose randomly*. – Karl Knechtel Mar 17 '23 at 06:10
12

If you don't want to use the random module, you can also try popitem():

>> d = {'a': 1, 'b': 5, 'c': 7}
>>> d.popitem()
('a', 1)
>>> d
{'c': 7, 'b': 5}
>>> d.popitem()
('c', 7)

Since the dict doesn't preserve order, by using popitem you get items in an arbitrary (but not strictly random) order from it.

Also keep in mind that popitem removes the key-value pair from dictionary, as stated in the docs.

popitem() is useful to destructively iterate over a dictionary

Community
  • 1
  • 1
patriciasz
  • 1,343
  • 9
  • 10
  • 35
    This is kind of bad, because if you load the dictionary in the same order on the same version of python you'll almost certainly get the same item. – Alex May 22 '14 at 17:43
  • See also: http://stackoverflow.com/questions/10593651/pythonic-way-to-access-arbitrary-element-from-dictionary – Ciro Santilli OurBigBook.com Nov 11 '16 at 11:01
  • 41
    python 3.6 dict is actually *ORDERED*! This is super important – Or Duan Jan 30 '17 at 16:01
  • 11
    This answer is just wrong. Even before 3.6 this will not give you a random value, but a value depending on the hash value ot the item. – OBu Jun 25 '18 at 20:27
  • 2
    Ignoring the incongruity with the OP's request, this way is a good way to get over the fact that `next` does not work with a dictionary as it is a mapping. (I came here for inspiration and this was it). – Matteo Ferla Nov 13 '18 at 10:19
  • `popitem()` would only return a random item, when you `shuffle` the `dict` first or you are somehow sure that it is already in random order. – phi Dec 02 '21 at 16:21
  • @MatteoFerla `next` works perfectly well with a dictionary *iterator*, which can easily be created by calling `iter` on the dictionary. This is how `for k in my_dict:` can work. – Karl Knechtel Mar 17 '23 at 06:15
12

Give a dictionary a, use:

import random
random_key = random.sample(a.keys(), 1)[0]
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
lavee_singh
  • 1,379
  • 1
  • 13
  • 21
  • 4
    `TypeError: Population must be a sequence or set. For dicts, use list(d).` – wim Oct 29 '20 at 06:21
  • 4
    `random_key = random.sample(a.keys(), 1)[0]` does work, however. – dlowe Sep 10 '21 at 12:02
  • @wim I can't easily check right now, but I think it worked with just `a` in 2.x. (Also, it's a little disconcerting that the exception message hard-codes a variable name not present in the code.) – Karl Knechtel Mar 17 '23 at 06:13
11

Call random.choice on the keys of the dictionary (the countries).

In 2.x, the keys can be chosen from directly:

>>> import random
>>> d = dict(Venezuela = 1, Spain = 2, USA = 3, Italy = 4)
>>> random.choice(d.keys())
'Venezuela'
>>> random.choice(d.keys())
'USA'

In 3.x, create a list first, e.g. random.choice(list(d.keys())).

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
user225312
  • 126,773
  • 69
  • 172
  • 181
  • 4
    Hi, I try to use your method to randomly pick one key from a given dictionary, but it does not work. My dictionary looks like a = {'walk': 20, 'run': 80} and when I use random.choice(a.keys()), there is an error like "dict_keys' object does not support indexing". Do you know what's wrong? Thanks a lot!!! – beepretty May 11 '16 at 04:50
  • 11
    @beepretty dict.keys() returns an iterable object, not a list-like object. To resolve the error, use `random.choice(list(d.keys()))`. – Greenstick Mar 23 '17 at 04:51
  • 3
    Use random.sample instead, which is cheaper than copying the keys to a list. – steveayre Aug 09 '18 at 13:35
  • 1
    @steveayre No, `random.sample` doesn't work with dict input. – wim Oct 29 '20 at 06:23
8

This works in Python 2 and Python 3:

A random key:

random.choice(list(d.keys()))

A random value

random.choice(list(d.values()))

A random key and value

random.choice(list(d.items()))
firelynx
  • 30,616
  • 9
  • 91
  • 101
5

Since the original post wanted the pair:

import random
d = {'VENEZUELA':'CARACAS', 'CANADA':'TORONTO'}
country, capital = random.choice(list(d.items()))

(python 3 style)

OBu
  • 4,977
  • 3
  • 29
  • 45
3

To get a random key, use random.choice(), passing the dictionary keys like so:

import random
keys = list(my_dict)
country = random.choice(keys)
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
srattigan
  • 665
  • 5
  • 17
3

Here are separate functions to get a key, value or item:

import random

def pick_random_key_from_dict(d: dict):
    """Grab a random key from a dictionary."""
    keys = list(d.keys())
    random_key = random.choice(keys)
    return random_key

def pick_random_item_from_dict(d: dict):
    """Grab a random item from a dictionary."""
    random_key = pick_random_key_from_dict(d)
    random_item = random_key, d[random_key]
    return random_item

def pick_random_value_from_dict(d: dict):
    """Grab a random value from a dictionary."""
    _, random_value = pick_random_item_from_dict(d)
    return random_value

These can be used like:

d = {...}
random_item = pick_random_item_from_dict(d)

These approaches only copy the keys of the dict, mitigating the need to copy the data in order to use random.choice. Once we have the key, we can get the corresponding value, and thus an item.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
2

If you don't want to use random.choice() you can try this way:

>>> list(myDictionary)[i]
'VENEZUELA'
>>> myDictionary = {'VENEZUELA':'CARACAS', 'IRAN' : 'TEHRAN'}
>>> import random
>>> i = random.randint(0, len(myDictionary) - 1)
>>> myDictionary[list(myDictionary)[i]]
'TEHRAN'
>>> list(myDictionary)[i]
'IRAN'
  • 1
    Pay attention: you generate a `list(…)` here multiple times. How about `myDictionary_list = list(myDictionary)`? – Cadoiz Jul 10 '20 at 23:05
  • While possible, the entire reason `random.choice` exists is in order to avoid the need to generate and use a random index. – Karl Knechtel Mar 17 '23 at 06:17
1

Since this is homework:

Check out random.sample() which will select and return a random element from an list. You can get a list of dictionary keys with dict.keys() and a list of dictionary values with dict.values().

carl
  • 49,756
  • 17
  • 74
  • 82
  • 5
    `random.sample` and `random.choice` can't work with iterators. They need to know the length of the sequence, which can't be determined from an iterator. – AFoglia Feb 01 '11 at 05:50
  • 4
    `random.sample` returns `k` random _elements_, `random.choice` returns a single random element – Anentropic Jan 30 '14 at 13:05
0

I am assuming that you are making a quiz kind of application. For this kind of application I have written a function which is as follows:

def shuffle(q):
"""
The input of the function will 
be the dictionary of the question
and answers. The output will
be a random question with answer
"""
selected_keys = []
i = 0
while i < len(q):
    current_selection = random.choice(q.keys())
    if current_selection not in selected_keys:
        selected_keys.append(current_selection)
        i = i+1
        print(current_selection+'? '+str(q[current_selection]))

If I will give the input of questions = {'VENEZUELA':'CARACAS', 'CANADA':'TORONTO'} and call the function shuffle(questions) Then the output will be as follows:

VENEZUELA? CARACAS
CANADA? TORONTO

You can extend this further more by shuffling the options also

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Anivarth
  • 619
  • 5
  • 19
  • 2
    You should not program drawing without replacement like this. Imagine drawing the 100th of 100 elements - 99% chance to hit an element inside of `selected_keys`. And you will likely repeat that about 100 times. At least delete the taken keys of q like `del(q[current_selection])` - you can overwrite q with the new shuffled `selected_keys` just like `q = selected_keys` after everything. Also don't forget about identing! Alternatively look at my `np.random.choice(...)` approach: https://stackoverflow.com/a/62843377/4575793 – Cadoiz Jul 10 '20 at 23:01
0

In Python 3.x, the objects returned by methods dict.keys(), dict.values() and dict.items() are view objects, which cannot be used directly with random.choice.

One option is to pass random.choice a list comprehension that extracts the candidate values to choose from:

import random

colors = {
    'purple': '#7A4198',
    'turquoise': '#9ACBC9',
    'orange': '#EF5C35',
    'blue': '#19457D',
    'green': '#5AF9B5',
    'red': ' #E04160',
    'yellow': '#F9F985'
}

color = random.choice([color_value for color_value in colors.values()]

print(f'The new color is: {color}')
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
  • This is redundant with prior answers; the list comprehension is simply a long-winded (and slower) way to get a list from the view. – Karl Knechtel Mar 17 '23 at 06:07
0

To select 50 random key values from a dictionary set dict_data:

sample = random.sample(set(dict_data.keys()), 50)
Aditya Raj
  • 29
  • 1
  • 4
0

I needed to iterate through ranges of keys in a dict without sorting it each time and found the Sorted Containers library. I discovered that this library enables random access to dictionary items by index which solves this problem intuitively and without iterating through the entire dict each time:

>>> import sortedcontainers
>>> import random
>>> d = sortedcontainers.SortedDict({1: 'a', 2: 'b', 3: 'c'})
>>> random.choice(d.items())
(1, 'a')
>>> random.sample(d.keys(), k=2)
[1, 3]
campkeith
  • 612
  • 8
  • 9
-1

Try this (using random.choice from items)

import random

a={ "str" : "sda" , "number" : 123, 55 : "num"}
random.choice(list(a.items()))
#  ('str', 'sda')
random.choice(list(a.items()))[1] # getting a value
#  'num'
-2

I found this post by looking for a rather comparable solution. For picking multiple elements out of a dict, this can be used:

idx_picks = np.random.choice(len(d), num_of_picks, replace=False) #(Don't pick the same element twice)
result = dict ()
c_keys = [d.keys()] #not so efficient - unfortunately .keys() returns a non-indexable object because dicts are unordered
for i in idx_picks:
    result[c_keys[i]] = d[i]
Cadoiz
  • 1,446
  • 21
  • 31
-3
b = { 'video':0, 'music':23,"picture":12 } 
random.choice(tuple(b.items())) ('music', 23) 
random.choice(tuple(b.items())) ('music', 23) 
random.choice(tuple(b.items())) ('picture', 12) 
random.choice(tuple(b.items())) ('video', 0) 
WhatsThePoint
  • 3,395
  • 8
  • 31
  • 53
  • 3
    Welcome to Stack Overflow! Thank you for this code snippet, which might provide some limited short-term help. A proper explanation [would greatly improve](//meta.stackexchange.com/q/114762) its long-term value by showing *why* this is a good solution to the problem, and would make it more useful to future readers with other, similar questions. Please [edit] your answer to add some explanation, including the assumptions you've made. – Toby Speight Jan 18 '18 at 11:07
-3

Here is a little Python code for a dictionary class that can return random keys in O(1) time. (I included MyPy types in this code for readability):

from typing import TypeVar, Generic, Dict, List
import random

K = TypeVar('K')
V = TypeVar('V')
class IndexableDict(Generic[K, V]):
    def __init__(self) -> None:
        self.keys: List[K] = []
        self.vals: List[V] = []
        self.dict: Dict[K, int] = {}

    def __getitem__(self, key: K) -> V:
        return self.vals[self.dict[key]]

    def __setitem__(self, key: K, val: V) -> None:
        if key in self.dict:
            index = self.dict[key]
            self.vals[index] = val
        else:
            self.dict[key] = len(self.keys)
            self.keys.append(key)
            self.vals.append(val)

    def __contains__(self, key: K) -> bool:
        return key in self.dict

    def __len__(self) -> int:
        return len(self.keys)

    def random_key(self) -> K:
        return self.keys[random.randrange(len(self.keys))]
Mike Gashler
  • 609
  • 7
  • 12