Disons que j'ai une liste x
avec une longueur inconnue à partir de laquelle je veux sauter un élément au hasard afin que la liste ne contienne pas l'élément par la suite. Quelle est la manière la plus pythonique de faire cela?
Je peux le faire en utilisant une combinaison plutôt peu pratique de pop
, random.randint
et len
, et j'aimerais voir des solutions plus courtes ou plus agréables:
import random
x = [1,2,3,4,5,6]
x.pop(random.randint(0,len(x)-1))
Ce que j'essaie de réaliser, c'est de faire apparaître consécutivement des éléments aléatoires dans une liste. (c'est-à-dire, pop aléatoirement un élément et le déplacer vers un dictionnaire, pop aléatoirement un autre élément et le déplacer vers un autre dictionnaire, ...)
Notez que j'utilise Python 2.6 et n'ai trouvé aucune solution via la fonction de recherche.
Réponses:
Ce que vous semblez faire ne semble pas très pythonique en premier lieu. Vous ne devriez pas supprimer des éléments du milieu d'une liste, car les listes sont implémentées sous forme de tableaux dans toutes les implémentations Python que je connais, c'est donc une
O(n)
opération.Si vous avez vraiment besoin de cette fonctionnalité dans le cadre d'un algorithme, vous devriez consulter une structure de données comme celle
blist
qui prend en charge la suppression efficace du milieu.En Python pur, ce que vous pouvez faire si vous n'avez pas besoin d'accéder aux éléments restants est simplement de mélanger d'abord la liste, puis de la parcourir:
lst = [1,2,3] random.shuffle(lst) for x in lst: # ...
Si vous avez vraiment besoin du reste (ce qui est un peu une odeur de code, à mon humble avis), au moins vous pouvez à
pop()
partir de la fin de la liste maintenant (ce qui est rapide!):while lst: x = lst.pop() # do something with the element
En général, vous pouvez souvent exprimer vos programmes avec plus d'élégance si vous utilisez un style plus fonctionnel, au lieu de changer d'état (comme vous le faites avec la liste).
la source
random.shuffle(x)
et ensuitex.pop()
? Je ne comprends pas comment faire cela "fonctionnel"?zip
les obtenir pour obtenir une liste de paires (dict, nombre). Vous avez dit quelque chose à propos de plusieurs dictionnaires dont vous souhaitez associer chacun à un nombre aléatoire.zip
est parfait pour celaVous n'obtiendrez pas beaucoup mieux que cela, mais voici une légère amélioration:
Documentation sur
random.randrange()
:la source
Pour supprimer un seul élément à un index aléatoire d'une liste si l'ordre du reste des éléments de la liste n'a pas d'importance:
import random L = [1,2,3,4,5,6] i = random.randrange(len(L)) # get random index L[i], L[-1] = L[-1], L[i] # swap with the last element x = L.pop() # pop last element O(1)
Le swap est utilisé pour éviter le comportement O (n) lors de la suppression du milieu d'une liste.
la source
Voici une autre alternative: pourquoi ne pas vous mélangez la liste d' abord , puis commencer à éclater les éléments de celui - ci jusqu'à plus restent des éléments? comme ça:
import random x = [1,2,3,4,5,6] random.shuffle(x) while x: p = x.pop() # do your stuff with p
la source
[for p in x]
Une façon de le faire est:
la source
pop
vous pouvez pointer un nom sur l'élément supprimé, avec cela vous ne pouvez pas.remove
nécessite un balayage linéaire de la liste. C'est terriblement inefficace par rapport à la recherche d'un index.Sans sortir de la liste, j'ai rencontré cette question sur Google en essayant d'obtenir X éléments aléatoires à partir d'une liste sans doublons. Voici ce que j'ai finalement utilisé:
items = [1, 2, 3, 4, 5] items_needed = 2 from random import shuffle shuffle(items) for item in items[:items_needed]: print(item)
Cela peut être légèrement inefficace car vous mélangez une liste entière mais n'en utilisez qu'une petite partie, mais je ne suis pas un expert en optimisation, donc je peux me tromper.
la source
random.sample(items, items_needed)
Je sais que c'est une vieille question, mais juste pour la documentation:
Si vous (la personne qui recherche la même question sur Google) faites ce que je pense que vous faites, c'est-à-dire sélectionner k nombre d'éléments au hasard dans une liste (où k <= len (votre liste)), mais en vous assurant que chaque élément n'est plus sélectionné plus d'une fois (= échantillonnage sans remplacement), vous pouvez utiliser random.sample comme le suggère @ jf-sebastian. Mais sans en savoir plus sur le cas d'utilisation, je ne sais pas si c'est ce dont vous avez besoin.
la source
Cette réponse est une gracieuseté de @ niklas-b :
" Vous souhaitez probablement utiliser quelque chose comme pypi.python.org/pypi/blist "
Pour citer la page PYPI :
On supposerait des performances réduites à la fin de l'accès aléatoire / exécution aléatoire , car il s'agit d'une structure de données «copie à l'écriture». Cela viole de nombreuses hypothèses de cas d'utilisation sur les listes Python, alors utilisez-le avec précaution .
CEPENDANT, si votre cas d'utilisation principal est de faire quelque chose d'étrange et de contre-nature avec une liste (comme dans l'exemple forcé donné par @OP, ou mon problème de file d'attente avec transfert Python 2.6 FIFO), cela conviendra parfaitement. .
la source
malgré de nombreuses réponses suggérant l'utilisation
random.shuffle(x)
etx.pop()
son très lent sur les données volumineuses. et le temps requis sur une liste d'10000
éléments a pris environ6 seconds
lorsque la lecture aléatoire est activée. lorsque la lecture aléatoire est désactivée, la vitesse était0.2s
la méthode la plus rapide après avoir testé toutes les méthodes données ci-dessus s'est avérée être écrite par @jfs
import random L = ['1',2,3,'4'...1000] #you can take mixed or pure list i = random.randrange(len(L)) # get random index L[i], L[-1] = L[-1], L[i] # swap with the last element x = L.pop() # pop last element O(1)
à l'appui de ma réclamation, voici le graphique de complexité temporelle de cette source
SI il n'y a pas de doublons dans la liste,
vous pouvez également atteindre votre objectif en utilisant des ensembles. une fois la liste transformée en doublons, elle sera supprimée.
remove by value
etremove random
coûtO(1)
, c'est-à-dire très efficace. c'est la méthode la plus propre que je puisse proposer.L=set([1,2,3,4,5,6...]) #directly input the list to inbuilt function set() while 1: r=L.pop() #do something with r , r is random element of initial list L.
Contrairement à
lists
quelleA+B
option de support ,sets
supporte égalementA-B (A minus B)
avecA+B (A union B)
etA.intersection(B,C,D)
. super utile lorsque vous souhaitez effectuer des opérations logiques sur les données.OPTIONNEL
SI vous voulez de la vitesse lorsque les opérations sont effectuées sur la tête et la queue de la liste, utilisez python dequeue (file d'attente double) à l'appui de ma réclamation, voici l'image. une image est mille mots.
la source