选择满足某个谓词的随机值的python方法

选择满足某个谓词的随机值的python方法,python,Python,假设我有一个元素列表,我想从列表中随机选择一个满足谓词的元素。什么是蟒蛇式的方法 我目前正在做一个理解,后面跟着一个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) 谢谢 我在文档中找不到类似于random的函数。请选择specific(list,predica

假设我有一个元素列表,我想从列表中随机选择一个满足谓词的元素。什么是蟒蛇式的方法

我目前正在做一个理解,后面跟着一个
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)

谢谢

我在文档中找不到类似于
random的函数。请选择specific(list,predicate)
,因此我将尝试以下方法:

import random
def selectspecific(l, predicate):
    result = random.choice(l)
    while (not predicate(result)):
        result = random.choice(l)
    return result

您在上面编写的方法实际上是一种很好的惯用python。如果我们分析算法,我们会发现它基本上是这样做的:

  • 列出满足谓词的元素。(随n线性增长)
  • 从该列表中选择一个随机元素。(恒定时间)
  • 唯一的另一种方法是随机选择一个元素,确定它是否满足谓词,如果不满足则再次选择。这个算法稍微复杂一点。在90%的列表满足谓词的情况下,这将比您的解决方案运行得快得多。在只有10%的列表满足谓词的情况下,它实际上会运行得慢得多,因为它很可能会随机选择给定的元素,并多次检查该元素上是否满足谓词。现在你可以考虑记忆你的谓词,但是你仍然会选择很多随机数据。归根结底,除非您的解决方案特别不适合您的数据,否则请坚持使用它,因为它很棒。就我个人而言,我会这样重写:

    intlist = range(1,10)
    randomeven = random.choice([i for i in intlist if i % 2 == 0])
    
    这稍微简洁一点,但它的运行方式将与您现有的代码完全相同

    这有多像蟒蛇

    from itertools import ifilterfalse
    from random import choice
    print choice([ i for i in ifilterfalse(lambda x: x%2, range(10)) ])
    

    如果希望封装更多内容,可以创建一个方法来处理选择,该方法将接受谓词方法。然后可以将此谓词方法与
    filter()
    一起使用

    您可以将谓词作为
    lambda
    或任何其他方法传递给
    selectSpecific()
    。例如:

    intlist = range(1,10)
    selectSpecific(intlist, lambda x: x % 2 == 0)
    
    def makeEven(n):
      if n % 2 == 0:
        return n
    
    selectSpecific(intlist, makeEven)
    

    即使是随机挑选者也必须知道从中选择什么。那一行额外的代码会伤害你吗?我认为这取决于谓词排除了多少项。如果小于50%,那么首先随机选择一个项目,然后测试谓词可能更有效。另一方面,如果只有少数项目符合您的谓词,那么事先筛选它们可能会更好。@Felix_Kling即使您从列表中排除的项目不到50%,也无法知道运行需要多长时间。我在itertools.ifilter上发布了相同的答案。但是它不起作用,因为random.choice需要知道数据的实际长度。当然这只是他问题中代码的可读性稍差的版本。带有lambda的过滤器实际上与list comprehension.nice相同。可以使用True/break Loop对其进行修改,使其符合DRY原则。如果无法知道此解决方案的成本,则可能需要“永远”才能从列表中获取有效元素。首先筛选似乎是最好的解决方案。如果列表中没有任何元素从
    谓词()返回True,则这将是无限循环。+1有时您希望拒绝样本。有时候,你不得不拒绝样本,比如当你不能列举所有可能的选择时。但是,在这种情况下,您不能使用
    random.choice
    。。。
    import random
    def selectSpecific(intlist, predicate):
      filteredList = filter(predicate, intlist)
      result = random.choice(filteredList)
      return result
    
    intlist = range(1,10)
    selectSpecific(intlist, lambda x: x % 2 == 0)
    
    def makeEven(n):
      if n % 2 == 0:
        return n
    
    selectSpecific(intlist, makeEven)