简体   繁体   中英

Most pythonic way to select at random an element in a list with conditions

I have two list:

list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list2 = [1, 4, 5]

I want to select an element from list1 but it shouldn't belongs to list2 .

I have a solution using a while loop but I would like to have a one liner more pythonic and elegant.

If your elements are unique you can use the set difference. (Convert list1 to a set and remove the elements from list2). Then draw a random sample.

random.choice(list(set(list1).difference(list2)))
[item for item in list1 if not in list2]

To make it a bit faster(because lookup in set faster than in list):

list2_items = set(list2)
[item for item in list1 if not in list2_items]

or with filter function(you will get a generator object in Python3

filter(lambda item: item not in list2, list1)

Converting list2 to set will also speed up filtering here.

To get more information read about list comprehensions .

Update: it seems that I missed a point about one random value. Well, you still can use list comprehensions, but use random.choice as was mentioned before:

import random
random.choice([item for item in list1 if not in list2_items])

It will filter choices and then get one randomly. @zeehio response looks like better solution.

import random
import itertools

next(item for item in (random.choice(list1) for _ in itertools.count()) if item not in list2)

That's equivalent to:

while True:
    item = random.choice(list1)
    if item not in list2:
        break

You would probably want to utilize set s like so:

list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list2 = [1, 4, 5]

import random

print(random.choice([x for x in set(list1).difference(list2)]))  # kudos @chepner

That way we randomly draw from set(list1) - set(list2) : elements in list1 but not in list2 . This approach also scales well as lists 1 & 2 become large.


As @MSeifert noticed, the conversion of list1 to set will remove any duplicate elements that might be present in list1 thus altering the probabilities. If list1 might contain duplicate elements in the general case you might want to do this instead:

print(random.choice([x for x in list1 if x not in list2]))

without importing random library:

print((list(set(list1) - set(list2))).pop())

inside pop() you can give the index of the element you want to select,it will pop out that element example : for selecting list of index 1(from new list) , ((list(set(list1) - set(list2))).pop(1))

Here this (list(set(list1) - set(list2)) code will create a new list which contains only list with items from the first list which aren't present in the second one,

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM