Randomly chose an element of one list that's NOT in a second list

Question:

Say I have a list2 of randomly chosen elements from a large list1. Is there a clever way of choosing an element from list1 that’s NOT already in list2?

For example:

list1 = range(20,100)
list2 = [37,49,22,35,72] # could be much longer
    
while True:
    n = random.choice(list1)
    if n not in list2:
        break
    
# now n is an element of list1 that's not in list2

I feel like there must be a more efficient way of doing this than a guess-and-check while-loop.

Asked By: vestlen

||

Answers:

In case that there are no repeating elements in list1, this is a pythonic way, working with set and -:

import random

list1 = range(20,100)
list2 = [37,49,22,35,72] # could be much longer

n = random.choice(tuple(set(list1)-set(list2)))

# now n is an element of list1 that's not in list2

The tuple call is needed to avoid a NotIndexable exception.

Answered By: Sebastian Wozny

You can subtract list2 of list1:

list3 = list(set(list1)-set(list2))

and choose from it randomly:

random.choice(list3)

Note: you need to reconvert the set to a list.

Answered By: agold

You could use:

import random

list1 = range(20,100)
list2 = [37,49,22,35,72]

not_in_list2 = [item for item in list1 if item not in list2]
n = random.choice(not_in_list2)

This uses a list comprehension to create a list of all elements in list1 that aren’t inlist2. It then selects randomly from this list. Unlike when working with sets, this technique does not change the probability of items being selected, because it does not remove duplicate elements from list1.

Answered By: gtlambert

If you want to randomly select more than one item from a list, or select an item from a set, it’s better to use random.sample instead of choice

import random
diff = set(list1)-set(list2)
num_to_select = 1 # set the number to select here.
list_of_random_items = random.sample(diff, num_to_select)
Answered By: Hooting

If you do not want the overhead of creating a new list (or a new list and two sets) which can become quite costly if list1 is very large, there is another option.

import random

list1 = range(20,100)
list2 = [37,49,22,35,72]

for i in list2:
    while i in list1:
        list1.remove(i)

random.choice(list1)

Just iterate through the items in list2 and remove them from list1. Since list.remove() only removes the first occurrence of an item, I added a while-loop to ensure that all occurences are removed.

Answered By: pzp
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.