Domanda

Mi scuso se questo è semplice, ma ho cercato per un po 'e ora non riesce a trovare una soluzione semplice e efficiente.

Ho un bidimensionale lista Python di liste, che consiste solo di 1 e 0..

per esempio:.

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

desidero ritorno, a caso, gli indici di un elemento casuale che è = 1. In questo caso desidero restituire uno:

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

con la stessa probabilità.

ho potuto iterare attraverso ogni elemento della struttura e compilare un elenco di indici ammissibili e scegliendo una a caso utilizzando random.choice (lista) - ma questo sembra molto lento e non posso fare a sensazione che ci sia un più ordinato, più Pythonic modo per avvicinarsi a questo. Farò questo per probabilmente una matrice 20x20 e dovranno farlo molte volte, così ho potuto fare con esso che è il più efficiente possibile.

Grazie in anticipo per qualsiasi aiuto e consiglio!

È stato utile?

Soluzione

userei una lista di comprensione per generare una lista di tuple (posizioni di 1), quindi 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))

Altri suggerimenti

I userebbe un NumPy array per raggiungere questo obiettivo:

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

Se il tuo memorizzare i dati in array numpy fin dall'inizio, questo approccio sarà probabilmente più veloce di qualsiasi cosa si può fare con una lista di liste.

Se si vuole fare scegliere molti indici per gli stessi dati, ci sono ancora più velocemente si avvicina.

random.choice ci permettono di scegliere un elemento a caso da un elenco , quindi abbiamo solo bisogno di utilizzare un elenco di comprensione per creare un elenco degli indici dove gli elementi sono 1 e poi scegliere una a caso.

Possiamo usare la lista di comprensione seguito:

>>> 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)]

Il che significa che possiamo fare:

>>> 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)

Se si farà questo molte volte può valere la pena cache l'elenco degli indici generati dalla comprensione e poi raccolta dal più volte, piuttosto che il calcolo della lista di comprensione ogni singola volta.

Quando si ottiene il risultato dal check random.choice se è come si vorrebbe che con gli elementi corretti, se non è ancora casuale

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

Modifica: per evitare confusione con modulo re, grazie

Un'altra idea potrebbe essere quella di memorizzare i dati in un modo completamente diverso: invece di una lista di liste, utilizzare un insieme di coppie indice che rappresenta la voci che sono 1. Nel tuo esempio, questo sarebbe

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

Per scegliere casualmente un paio di indice, l'uso

random.choice(list(s))

Per impostare una voce a 1, l'uso

s.add((i, j))

Per impostare una voce a 0, l'uso

s.remove((i, j))

Per capovolgere una voce, l'uso

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

Per controllare se una voce è 1, l'uso

(i, j) in s
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top