【问题标题】:Selecting random elements in a list conditional on attribute以属性为条件在列表中选择随机元素
【发布时间】:2016-02-15 04:51:06
【问题描述】:
class Agent:
    def __init__(self, state):
        self.state = state
#initialize values
state_0_agents = 10
state_1_agents = 10
numberofselections = 2 #number of agents who can choose to transition to the higher plane

#list of agents
agents = [Agent(0) for i in range(state_0_agents)]
agents.extend(Agent(1) for i in range(state_1_agents))

random.choice(agents) 

你好! 所以我想从这个代理列表中随机选择几个代理,我最终将其状态更改为 1。不幸的是,随机选择函数在所有元素中进行选择。但是我只想随机选择那些状态为 0 的人。

如果可以在不创建新列表的情况下发生这种情况,我更愿意。

【问题讨论】:

  • 我认为您的选择是创建一个新列表然后从中进行选择,或者反复随机选择直到您选择的列表状态==0。
  • 您要么必须创建一个新列表,要么继续重试random.choice() 调用,直到它返回一个将.state 设置为0 的调用。
  • 如果我继续重试随机选择,那么可能在一段时间内什么都不会发生。

标签: python list random


【解决方案1】:

我在这里看到 3 个选项:

  • 无论如何都要创建一个列表,您可以通过列表推导来做到这一点:

    random.choice([a for a in agents if a.state == 0])
    
  • 将random.choice() 调用放入一个循环中,继续尝试,直到找到符合条件的调用:

    while True:
        agent = random.choice(agents)
        if agent.state == 0:
            break
    
  • 索引您的agents 列表,然后从该索引中选择;这些实际上仍然只是列表:

    agent_states_index = {}
    for index, agent in enumerate(agents):
        agent_states_index.setdefault(agent.state, []).append(index)
    
    agent_index = random.choice(agent_states_index[0])
    agent = agents[agent_index]
    

【讨论】:

  • 太棒了!谢谢!那个假名单让我有点头疼,但它确实有效!
【解决方案2】:

我知道有四种算法。

第一个在this answer中有详细说明。遍历数组,然后如果遇到满足条件的元素,检查随机整数是否小于(1/(however many elements you've passed that satisfy the condition))。

第二个是遍历您的数组,将满足条件的元素添加到新数组中,然后从该列表中随机挑选一个。

这两种算法都在 O(n) 时间内运行,其中 n 是数组的大小。如果元素存在并且满足条件,他们保证会找到它。

还有另外两种更快的算法。它们都在 O(1) 时间内运行,但有一些主要弱点。

第一个是随机选择索引,直到找到满足条件的索引。这具有潜在的无限时间复杂度,但实际上是 O(1)。 (如果满足条件的元素很少,而数组很大,比如万分之一,这会变慢。)如果一个元素不存在,也不能保证找到;如果没有满足条件的元素,你要么有一个无限循环,要么必须编写算法来进行有限次数的猜测,即使有一个元素,你也可能会错过它。

第二种是选择一个随机索引,然后不断递增,直到找到满足条件的索引。保证找到可接受的索引或查看所有索引而不进入无限循环。它的缺点是不完全随机。显然,如果您每次将索引增加 1,它将是真的,真的 非随机的(如果数组中有一堆可接受的索引)。但是,如果您从与数组元素数互质的少数数字之一中随机选择增量,那么它仍然不是公平和随机的,而是相当公平和随机的,并且可以保证成功。

同样,这最后 2 种算法非常快,但要么不能保证有效,要么不能保证完全随机。我不知道有一种算法既快速又能保证工作,而且完全公平和随机。

【讨论】:

  • 我可能应该指定,如果你有记忆,最好的方法可能是创建一个新列表(如在 Martijn 的响应中)或使用由旧列表制成的 numpy 数组(像 Antonvh 的回应),但原帖说不要那样做。
【解决方案3】:

使用 numpy.where:

import numpy as np

class Agent:
    def __init__(self, state):
        self.state = state

#initialize values
state_0_agents = 10
state_1_agents = 10

#list of agents
agents = [0]*state_0_agents
agents += [1]*state_1_agents

selected_agent_idx = random.choice(np.where(np.array(agents) == 0))

【讨论】:

    【解决方案4】:

    您还可以在 numpy 中使用 nonzero 函数,因为它返回一个可迭代不为零的索引列表。然后您可以将它与choice 函数结合使用,以更改该列表的元素索引中的随机值:

    import numpy as np
    index_agent0 = np.nonzero(agents==0)[0]
    agents[np.random.choice(index_agent0)] = 1
    
    

    【讨论】:

      猜你喜欢
      • 2021-12-30
      • 2012-03-12
      • 2018-03-25
      • 2013-10-19
      • 1970-01-01
      • 2014-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多