Bagaimana cara mengurutkan (scramble) array secara acak di Ruby?

128

Saya ingin item array saya diacak. Sesuatu seperti ini:

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

dan seterusnya, secara acak

Daniel Cukier
sumber

Jawaban:

293

Dibangun sekarang:

[1,2,3,4].shuffle => [2, 1, 3, 4]
[1,2,3,4].shuffle => [1, 3, 2, 4]
Ron Gejman
sumber
3
Dan jika Anda ingin menerapkannya sendiri: en.wikipedia.org/wiki/Fisher-Yates_shuffle
Joey
Atau jika Anda menginginkannya untuk Ruby <1.9: memerlukan 'backports'
Marc-André Lafortune
1
Sepertinya itu ada di Ruby 1.8.7 juga.
Brian Armstrong
Benar-benar luar biasa.
sidney
1
Hanya ingin menambahkan: jika Anda ingin memengaruhi koleksi, tambahkan !setelah panggilan untuk mengacak. Tanpa !array shuffled dikembalikan, dan matang untuk tugas.
Muyiwa Olu
27

Untuk ruby ​​1.8.6 (yang tidak memiliki shuffle bawaan):

array.sort_by { rand }
sepp2k
sumber
11
@Josh: Halaman yang Anda tautkan menjelaskan algoritma yang sama sekali berbeda. Perhatikan bahwa sort_byfungsi ruby tidak berfungsi seperti fungsi sortir javascript (atau fungsi sortir ruby ​​dalam hal ini), yang hanya peduli apakah angka yang dihitung kurang dari nol, nol atau lebih besar dari nol. Alih-alih sort_bymengingat nilai yang dihitung untuk setiap item dan kemudian mengurutkan item dengan nilai itu. Jadi dalam hal ini setiap item diberi nomor acak dan kemudian array diurutkan berdasarkan angka-angka acak itu.
sepp2k
Dengan array ukuran besar jenis ini dengan angka acak untuk setiap item mungkin memakan waktu terlalu lama (O (NLogN), kita bisa melakukannya dalam waktu linier jika kita menghasilkan angka acak dari item sebelumnya yang telah kita kocok dan lalu tukar sebagai iterator increment
Downhillski
9

Untuk ruby ​​1.8.6 sebagai contoh sepp2k, tetapi Anda tetap ingin menggunakan metode "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]

Bersulang

bry4n
sumber
2

Kode dari Gem Backports hanya untuk Array untuk Ruby 1.8.6. Ruby 1.8.7 atau lebih tinggi sudah ada di dalamnya.

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
sumber
0

The Ruby Aspek perpustakaan ekstensi memiliki Randommodul yang menyediakan metode yang berguna termasuk shuffledan shuffle!untuk sekelompok kelas inti termasuk Array, Hashdan String.

Berhati-hatilah jika Anda menggunakan Rails karena saya mengalami beberapa bentrokan yang tidak menyenangkan dalam cara monkeypatchingnya berbenturan dengan Rails ...

edavey
sumber