【问题标题】:Returning random element from a Python array based on search criteria根据搜索条件从 Python 数组中返回随机元素
【发布时间】:2011-05-13 23:25:21
【问题描述】:

抱歉,如果这很简单,但我一直在寻找一段时间,找不到简单、有效的解决方案。

我有一个仅由 1 和 0 组成的二维 Python 列表。

例如:

a=[[0,1,0],[0,1,1],[1,0,1]]

我希望随机返回 = 1 的随机元素的索引。在这种情况下,我希望返回:

[0,1], [1,1], [1,2], [2,0], or [2,2]

概率相等。

我可以遍历结构中的每个元素并编译一个符合条件的索引列表,然后使用 random.choice(list) 随机选择一个 - 但这似乎很慢,我不禁觉得有一个更整洁的,更 Pythonic 的方式来解决这个问题。我可能会为一个 20x20 的阵列执行此操作,并且需要执行多次,因此我可以尽可能高效地执行此操作。

提前感谢您的任何帮助和建议!

【问题讨论】:

  • 你确定你有一个数组吗?还是列表列表?
  • “很多次”是指在同一个数组上做多次,还是针对不同的数组?
  • 抱歉,列表列表。我的错。我会更正帖子。
  • 我需要多次对同一个数组执行此操作,但数组中的元素不会是静态的。每隔一段时间,某些元素的值就会翻转。
  • “数组”是静态的吗(你提到a 20x20 array)?如果是这样,您可以生成一次可能性并继续使用该列表作为随机数的输入。

标签: python arrays search indices


【解决方案1】:

另一个想法是以完全不同的方式存储数据:使用一组索引对来表示为 1 的条目,而不是列表列表。在您的示例中,这将是

s = set((0, 1), (1, 1), (1, 2), (2, 0), (2, 2))

要随机选择一个索引对,请使用

random.choice(list(s))

要将条目设置为 1,请使用

s.add((i, j))

要将条目设置为 0,请使用

s.remove((i, j))

要翻转条目,请使用

s.symmetric_difference_update([(i, j)])

要检查条目是否为 1,请使用

(i, j) in s

【讨论】:

    【解决方案2】:

    random.choice 允许我们从列表中随机选择一个元素,因此我们只需要使用列表推导式创建一个元素为 1 的索引列表,然后随机选择一个。

    我们可以使用以下列表推导:

    >>> a = [[0,1,0],[0,1,1],[1,0,1]]
    >>> [(x,y) for x in range(len(a)) for y in range(len(a[x])) if a[x][y] == 1]
    [(0, 1), (1, 1), (1, 2), (2, 0), (2, 2)]
    

    这意味着我们可以做到:

    >>> import random
    >>> random.choice([(x,y) for x in range(len(a)) for y in range(len(a[x])) if a[x][y] == 1])
    (1, 1)
    

    如果您要多次执行此操作,则可能值得缓存由推导生成的索引列表,然后从中挑选几次,而不是每次都计算列表推导。

    【讨论】:

      【解决方案3】:

      我会使用NumPy 数组来实现这一点:

      from numpy import array
      random_index = tuple(random.choice(array(array(a).nonzero()).T))
      

      如果您从一开始就将数据存储在 NumPy 数组中,那么这种方法可能比您对列表执行的任何操作都更快。

      如果您想为相同的数据选择多个索引,还有更快的方法。

      【讨论】:

        【解决方案4】:

        当你从 random.choice 得到你的结果时,检查它是否是你想要的,如果它不再是随机的,那么使用正确的元素

        def return_random(li):
            item = random.choice(li)
            if item == 1: #insert check here
                return item
            else:
                return_random(li)
        

        编辑:避免与 re 模块混淆,谢谢

        【讨论】:

        • 不应使用常用的re 作为变量。这可能会令人困惑。
        • 谢谢,这真的很有帮助,我没有考虑这样做。一个潜在的问题是,有时列表中的 1 可能非常稀疏,在这种情况下,这种方法可能非常低效。但我当然可以试一试,因为在我实际运行代码并查看之前,我不知道这是否是个问题。
        • 担心以后优化。你总是可以优化一个工作程序,但它很难加速,实际上并没有处理
        【解决方案5】:

        我会使用列表推导生成一个元组列表(位置为 1),然后是 random.choice :

        from random import choice
        
        a = [[0,1,0],[0,1,1],[1,0,1]]
        mylist = []
        
        [[mylist.append((i,j)) for j, x in enumerate(v) if x == 1] for i, v in enumerate(a)]
        print(choice(mylist))
        

        【讨论】:

        • 这看起来绝对是我正在寻找的完美答案,谢谢!我试图按照这些思路思考一些东西,但我的 Python 还没有完全适应它。
        • @Scott,欢迎来到 StackOverflow!刚刚注意到你似乎喜欢这个答案。 StackOverflow 的一个很酷的事情是,如果每个人都正确使用它,它就会自我改进:最好的答案会得到“选择”并投票。如果您喜欢这个,它不仅会奖励回答者,而且如果您投票给好的答案并接受您最喜欢的问题答案,也会改善网站。
        • @Cpfohl - 我刚刚注册并尝试过,但它说我需要至少 15 个声望。我想这是因为我是新手,但如果可以的话,我会投票!
        • @Scott:您可以“接受”其中一个答案——您认为最能回答问题的答案。只需单击该答案旁边的复选标记即可。
        • @Scott:感谢参与!希望如此。对你有帮助。附言您将获得 2 个代表。接受答案,提出一个被投票的好问题得 5 分。两个好问题,接受 3 个答案,你很快就会达到 15 个。
        猜你喜欢
        • 2019-08-21
        • 2019-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-06
        • 1970-01-01
        • 2010-10-13
        • 2021-11-10
        相关资源
        最近更新 更多