2010-11-22 21 views
2

Excuses si cela est simple, mais j'ai cherché un peu de temps maintenant et ne peux pas trouver une solution simple et efficace.Renvoi d'un élément aléatoire à partir d'un tableau Python basé sur des critères de recherche

J'ai une liste Python bidimensionnelle de listes qui ne comprend que des 1 et des 0.

par exemple:

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

Je voudrais revenir, au hasard, les indices d'un élément aléatoire qui est = 1. Dans ce cas, je voudrais revenir soit:

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

avec une probabilité égale.

Je pourrais parcourir tous les éléments de la structure et compiler une liste d'indices admissibles, puis en choisir un au hasard en utilisant random.choice (liste) - mais cela semble très lent et je ne peux pas m'empêcher de penser qu'il y a un plus , plus de façon Pythonienne d'aborder cela. Je le ferai probablement pour un tableau 20x20 et je devrai le faire plusieurs fois, donc je pourrais le faire aussi efficacement que possible.

Merci d'avance pour toute aide et conseil!

+0

Êtes-vous sûr que vous avez un tableau? Ou est-ce une liste de listes? –

+0

est-ce que "plusieurs fois" fait référence au fait de le faire sur le même tableau plusieurs fois, ou pour des tableaux différents? – lijie

+0

Désolé, liste des listes. Mon erreur. Je vais corriger le post. – Scott

Répondre

2

j'utiliser une compréhension de la liste pour générer une liste de tuples (positions de 1), puis 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)) 
+0

Cela semble absolument la réponse parfaite que je cherchais, merci! J'essayais de penser à quelque chose dans ce sens, mais mon Python n'était pas tout à fait à la hauteur. – Scott

+0

@Scott, bienvenue dans StackOverflow! J'ai juste remarqué que tu semblais aimer cette réponse. L'un des avantages de StackOverflow est qu'il s'améliore automatiquement si tout le monde l'utilise correctement: les meilleures réponses sont choisies et votées. Si vous aimez celui-ci, non seulement il récompense le répondant, mais il améliore aussi le site si vous votez pour de bonnes réponses, et acceptez votre réponse préférée à vos questions. – Crisfole

+0

@Cpfohl - Je viens d'enregistrer et essayé, mais il dit que j'ai besoin d'au moins 15 réputation. Je suppose que c'est parce que je suis un débutant, mais je voterais si je pouvais! – Scott

0

Lorsque vous obtenez votre résultat de vérifier random.choice si elle est comment vous voulez avec les éléments corrects si elle est pas aléatoire à nouveau

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

Edit: pour éviter toute confusion avec le module re, grâce

+0

Ne devrait pas utiliser bien 're' comme variable. Cela peut être déroutant. – Danosaure

+0

Merci, c'est vraiment utile et je n'avais pas envisagé de le faire de cette façon. Un problème potentiel est que parfois les listes peuvent être très peu peuplées avec des 1, auquel cas cette méthode peut être très inefficace. Mais je peux certainement faire un essai car je ne saurai pas si c'est un problème jusqu'à ce que je cours réellement le code et vois. – Scott

+0

Inquiétude à propos de l'optimisation plus tard. Vous pouvez toujours optimiser un programme de travail, mais il est difficile d'accélérer ce qui ne fonctionne pas réellement –

1

Je voudrais utiliser un tableau NumPy à y parvenir:

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

Si votre magasin vos données dans des tableaux numpy dès le début, cette approche sera probablement plus rapide que tout ce que vous pouvez faire avec une liste de listes.

Si vous voulez choisir plusieurs indices pour les mêmes données, il y a des approches encore plus rapides.

1

random.choice nous permettent de choisir un élément au hasard dans une liste, donc nous avons juste besoin d'utiliser une compréhension de liste pour créer une liste des indices où les éléments sont 1 et puis choisir un au hasard.

Nous pouvons utiliser la compréhension de la liste de suivi:

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

Ce qui signifie que nous pouvons faire:

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

Si vous allez faire cela plusieurs fois il peut être utile mise en cache la liste des index générés par la compréhension, puis en choisissant plusieurs fois plutôt que de calculer la compréhension de la liste à chaque fois.

0

Une autre idée serait de stocker les données d'une manière complètement différente: Au lieu d'une liste de listes, utilisez un ensemble de paires d'index représentant les entrées qui sont 1.Dans votre exemple, ce serait

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

Pour choisir au hasard une paire d'index, utilisez

random.choice(list(s)) 

Pour définir une entrée à 1, utilisez

s.add((i, j)) 

Pour définir une entrée à 0 , utilisez

s.remove((i, j)) 

Pour retourner une entrée, utilisez

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

Pour vérifier si une entrée est 1, utilisez

(i, j) in s