问题
I have a 2D list of booleans. I want to select a random index from the the list where the value is False
. For example, given the following list:
[[True, False, False],
[True, True, True],
[False, True, True]]
The valid choices would be: [0, 1]
, [0, 2]
, and [2, 0]
.
I could keep a list of valid indices and then use random.choice
to select from it, but it seems unpythonic to keep a variable and update it every time the underlying list changes for only this one purpose.
Bonus points if your answer runs quickly.
回答1:
We can use a oneliner like:
import numpy as np
from random import choice
choice(np.argwhere(~a))
With a
the array of booleans.
This works as follows: by using ~a
, we negate the elements of the array. Next we use np.argwhere
to construct a k×2-array: an array where every row has two elements: for every dimension the value such that the corresponding value has as value False
.
By choice(..)
we thus select a random row. We can however not use this directly to access the element. We can use the tuple(..)
constructor to cast it to a tuple:
>>> tuple(choice(np.argwhere(~a)))
(2, 0)
You can thus fetch the element then with:
t = tuple(choice(np.argwhere(~a)))
a[t]
But of course, it is not a surprise that:
>>> t = tuple(choice(np.argwhere(~a)))
>>> a[t]
False
回答2:
My non-numpy version:
result = random.choice([
(i,j)
for i in range(len(a))
for j in range(len(a[i]))
if not a[i][j]])
Like Willem's np
version, this generates a list of valid tuples and invokes random.choice()
to pick one.
Alternatively, if you hate seeing range(len(...))
as much as I do, here is an enumerate()
version:
result = random.choice([
(i, j)
for i, row in enumerate(a)
for j, cell in enumerate(row)
if not cell])
回答3:
Assuming you don't want to use numpy.
matrix = [[True, False, False],
[True, True, True],
[False, True, True]]
valid_choices = [(i,j) for i, x in enumerate(matrix) for j, y in enumerate(x) if not y]
random.choice(valid_choices)
With list comprehensions, you can change the if condition (if not y
) to suit your needs. This will return the coordinate that is randomly selected, but optionally you could change the value part of the list comprehension (i,j)
in this case to: y
and it'd return false, though thats a bit redundant in this case.
来源:https://stackoverflow.com/questions/48631962/how-to-pythonically-select-a-random-index-from-a-2d-list-such-that-the-correspon