Comment trier (brouiller) au hasard un tableau dans Ruby?

128

J'aimerais que mes éléments de tableau soient brouillés. Quelque chose comme ça:

[1,2,3,4].scramble => [2,1,3,4]
[1,2,3,4].scramble => [3,1,2,4]
[1,2,3,4].scramble => [4,2,3,1]

et ainsi de suite, au hasard

Daniel Cukier
la source

Réponses:

293

Construit maintenant:

[1,2,3,4].shuffle => [2, 1, 3, 4]
[1,2,3,4].shuffle => [1, 3, 2, 4]
Ron Gejman
la source
3
Et si vous souhaitez l'implémenter vous-même: en.wikipedia.org/wiki/Fisher-Yates_shuffle
Joey
Ou si vous le voulez pour Ruby <1.9: nécessite des 'backports'
Marc-André Lafortune
1
On dirait que c'est aussi dans Ruby 1.8.7.
Brian Armstrong
C'est vraiment génial.
sidney
1
Je voulais juste ajouter: si vous voulez affecter la collection, ajoutez un !après l'appel à la lecture aléatoire. Sans le, !le tableau mélangé est retourné et mûr pour une affectation.
Muyiwa Olu
27

Pour ruby ​​1.8.6 (qui n'a pas de shuffle intégré):

array.sort_by { rand }
sepp2k
la source
11
@Josh: La page à laquelle vous avez lié décrit un algorithme entièrement différent. Notez que la sort_byfonction de ruby ne fonctionne pas comme la fonction de tri de javascript (ou la fonction de tri de ruby ​​d'ailleurs), qui se soucie uniquement de savoir si le nombre calculé est inférieur à zéro, zéro ou supérieur à zéro. Au lieu sort_byde cela, il se souvient de la valeur calculée pour chaque élément, puis trie les éléments par cette valeur. Donc, dans ce cas, chaque élément se voit attribuer un nombre aléatoire, puis le tableau est trié par ces nombres aléatoires.
sepp2k
Avec un tableau de grande taille, ce tri par les nombres aléatoires pour chaque élément peut prendre trop de temps (O (NLogN), nous pourrions le faire en un temps linéaire si nous générons un nombre aléatoire à partir des éléments précédents que nous avons mélangés, puis échangez comme le incrément de l'itérateur.
Downhillski
9

Pour ruby ​​1.8.6 comme exemple de sepp2k, mais vous voulez toujours utiliser la méthode "shuffle".

class Array
  def shuffle
    sort_by { rand }
  end
end

[1,2,3,4].shuffle #=> [2,4,3,1]
[1,2,3,4].shuffle #=> [4,2,1,3]

à votre santé

bry4n
la source
2

Code de la gemme Backports uniquement pour le tableau pour Ruby 1.8.6. Ruby 1.8.7 ou supérieur est intégré.

class Array
  # Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
  def shuffle
    dup.shuffle!
  end unless method_defined? :shuffle

  # Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
  def shuffle!
    size.times do |i|
      r = i + Kernel.rand(size - i)
      self[i], self[r] = self[r], self[i]
    end
    self
  end unless method_defined? :shuffle!
end
Vizjerai
la source
0

La bibliothèque d'extensions Ruby Facets a un Randommodule qui fournit des méthodes utiles, y compris shuffleet shuffle!à un tas de classes de base, y compris Array, Hashet String.

Faites juste attention si vous utilisez Rails car j'ai vécu des affrontements désagréables dans la façon dont son monkeypatching s'est heurté à Rails '...

Edavey
la source