Как случайным образом отсортировать (зашифровать) массив в Ruby?

128

Я бы хотел, чтобы элементы моего массива были перемешаны. Что-то вроде этого:

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

и так далее, случайным образом

Даниэль Кукьер
источник

Ответы:

293

Встроено сейчас:

[1,2,3,4].shuffle => [2, 1, 3, 4]
[1,2,3,4].shuffle => [1, 3, 2, 4]
Рон Гейман
источник
3
И если вы хотите реализовать это самостоятельно: en.wikipedia.org/wiki/Fisher-Yates_shuffle
Joey
Или, если вы хотите, чтобы это было для Ruby <1.9: требуйте backports
Марк-Андре Лафортюн
1
Похоже, это тоже в Ruby 1.8.7.
Брайан Армстронг,
Это потрясающе.
Сидни
1
Просто хотел добавить: если вы хотите повлиять на коллекцию, добавьте !после вызова в случайном порядке. Без !перетасованного массива возвращается и готов к присваиванию.
Muyiwa Olu
27

Для Ruby 1.8.6 (в котором нет встроенного перемешивания):

array.sort_by { rand }
sepp2k
источник
11
@Josh: На странице, на которую вы ссылаетесь, описан совершенно другой алгоритм. Обратите внимание, что sort_byфункция ruby не работает как функция сортировки javascript (или функция сортировки ruby ​​в этом отношении), которая заботится только о том, является ли вычисленное число меньше нуля, нуля или больше нуля. Вместо этого sort_byзапоминает вычисленное значение для каждого элемента, а затем сортирует элементы по этому значению. Итак, в этом случае каждому элементу присваивается случайное число, а затем массив сортируется по этим случайным числам.
sepp2k 05
С массивом большого размера такая сортировка по случайным числам для каждого элемента может занять слишком много времени (O (NLogN), мы могли бы сделать это за линейное время, если сгенерируем случайное число из предыдущих элементов, которые мы перемешали, а затем поменяем местами как инкремент итератора
Даунхиллски
9

Для ruby ​​1.8.6, как в примере с sepp2k, но вы все равно хотите использовать метод "перемешивания".

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]

ура

bry4n
источник
2

Код из Backports Gem только для массива для Ruby 1.8.6. Ruby 1.8.7 или выше встроен.

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
источник
0

Рубин Грань библиотека расширений имеет Randomмодуль , который содержит полезные методы , включая shuffleи shuffle!к связке основных классов , включая Array, Hashи String.

Просто будьте осторожны, если вы используете Rails, так как я столкнулся с некоторыми неприятными конфликтами в том, как его monkeypatching столкнулся с Rails ...

edavey
источник