питонический способ выбора случайного значения, удовлетворяющего определенному предикату - PullRequest
2 голосов
/ 14 мая 2010

Предположим, у меня есть список элементов, и я хочу случайным образом выбрать элемент из списка, который удовлетворяет предикату. Каков питонный способ сделать это?

В настоящее время я делаю понимание, за которым следует random.choice(), но это излишне неэффективно:

intlist = [1,2,3,4,5,6,7,8,9]
evenlist = [ i for i in intlist if i % 2 == 0 ] 
randomeven = random.choice(evenlist)

Спасибо!

Ответы [ 5 ]

2 голосов
/ 14 мая 2010

То, как вы написали это выше, на самом деле хороший идиоматический питон. Если мы проанализируем алгоритм, то обнаружим, что он по сути делает это:

  1. Составление списка элементов, удовлетворяющих предикату. (Растет линейно с n)
  2. Выбор случайного элемента из этого списка. (Постоянное время)

Единственный другой способ сделать это - выбрать элемент случайным образом, решить, удовлетворяет ли он предикату, и еще раз выбрать, если нет. Этот алгоритм немного сложнее. В случае, когда 90% списка удовлетворяет предикату, это будет выполняться намного быстрее, чем ваше решение. В случае, когда только 10% списка удовлетворяет предикату, он на самом деле будет работать намного медленнее, поскольку есть большая вероятность, что он случайным образом выберет данный элемент и проверит, удовлетворяется ли предикат для этого элемента более одного раза. Теперь вы можете подумать о запоминании своего предиката, но вы все равно будете выбирать много случайных данных. Это сводится к следующему: если ваше решение не особенно подходит для ваших данных, придерживайтесь его, потому что это здорово. Лично я бы переписал это так:

intlist = range(1,10)
randomeven = random.choice([i for i in intlist if i % 2 == 0])

Это немного более кратко, но будет работать точно так же, как ваш существующий код.

1 голос
/ 14 мая 2010
import random

intlist = [1,2,3,4,5,6,7,8,9]
randomeven = random.choice(filter(lambda x: x % 2 == 0, intlist))                                                                                                                                                         
1 голос
/ 14 мая 2010

Я не смог найти функцию вида random.selectspecific(list, predicate) в документации, поэтому я бы попробовал что-то вроде следующего:

import random
def selectspecific(l, predicate):
    result = random.choice(l)
    while (not predicate(result)):
        result = random.choice(l)
    return result
0 голосов
/ 14 мая 2010

Если вы хотите инкапсулировать больше, вы можете создать метод для обработки выделения, который будет принимать метод предиката. Затем вы можете использовать этот метод предиката с filter().

import random
def selectSpecific(intlist, predicate):
  filteredList = filter(predicate, intlist)
  result = random.choice(filteredList)
  return result

Вы можете передать предикат selectSpecific() как lambda или любым другим способом. Пример:

intlist = range(1,10)
selectSpecific(intlist, lambda x: x % 2 == 0)

def makeEven(n):
  if n % 2 == 0:
    return n

selectSpecific(intlist, makeEven)
0 голосов
/ 14 мая 2010

Насколько это питон?

from itertools import ifilterfalse
from random import choice
print choice([ i for i in ifilterfalse(lambda x: x%2, range(10)) ])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...