user775093
user775093

Reputation: 749

Extracting a random sublist from a list in Python

I have a python dictionary as follows:

{'APPLE_PROVIDERS' : ["some", "provider","can","be", "null"],
  ....
}

What i want to do is get a random sublist from the list (which is a value) of a key. Not just one element, but a totally random sublist. Here is what I tried:

a_list = a_dict.get('APPLE_PROVIDERS', "")
for item in a_list[randrange(0,len(a_list)) : randrange(0,len(a_list))]:
  ...do something.. 

This thing has two problems :

  1. If the list is empty, or if the dict lookup fails, the program fails since randrange has (0,0) as arguments, which results in an error

  2. Many times both randrange() calls generate the same number, especially when the list is small. This returns an empty list. For example a_list[5:5]

So what is the best way to get a random sublist with above cases handled ? Also, I do not care about the ordering. Anything works. I just want a totally random sublist of either 0,1... till len(a_list) elements each time the for loop starts.

If the list can be changed in some other data structure which can hold similar elements, that works for me too.

Upvotes: 20

Views: 25163

Answers (4)

John La Rooy
John La Rooy

Reputation: 304147

>>> from random import randint
>>> left = randint(0, len(L))
>>> right = randint(left, len(L))
>>> L[left:right]
['null']

if you don't want the possiblity of empty lists

>>> left = randint(0, len(L) - 1)
>>> right = randint(left + 1, len(L))

Upvotes: 7

Nafiul Islam
Nafiul Islam

Reputation: 82470

So, assuming that you want an empty list returned if you get an empty list, here's an example solution:

from random import shuffle

def get_random_sublist(the_dict, key, number):
    l = the_dict.get(key, [])
    shuffle(l)
    return l[:number]

So, I'd use random.shuffle. This allows me to avoid the issue of asking for a sublist that's larger than the actual list that we get.

>>> DICT = {'a' : "1 2 3 4 5".split(), 'b': [], 'c': [1]}
>>> get_random_sublist(DICT, 'a', 3)
['4', '1', '2']
>>> get_random_sublist(DICT, 'b', 10)
[]

Upvotes: 1

El'endia Starman
El'endia Starman

Reputation: 2244

Ignacio's answer is great. If you want to minimally modify your code, you can do this:

a_list = a_dict.get('APPLE_PROVIDERS', "")
if len(a_list) > 1:
    index1 = randrange(0,len(a_list)-1)
    index2 = randrange(index1+1,len(a_list))
    for item in a_list[index1:index2]:
        pass #do stuff

I do two things here: 1) I check to see if a_list has more than one element, and 2) I generate indices using randrange, but in such a way that the second is guaranteed to be greater than the first.

Upvotes: 2

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798626

Sample it.

>>> random.sample(["some", "provider", "can", "be", "null"], 3)
['some', 'can', 'provider']
>>> random.sample(["some", "provider", "can", "be", "null"], 3)
['can', 'null', 'provider']
>>> random.sample(["some", "provider", "can", "be", "null"], 3)
['null', 'some', 'provider']

Upvotes: 37

Related Questions