【问题标题】:How can I shuffle an array/hash in Ruby?如何在 Ruby 中打乱数组/散列?
【发布时间】:2023-03-03 16:02:01
【问题描述】:

出于学习目的,这叫什么?创建的对象是数组还是散列?

stack_of_cards = []

这就是我的填充方式:

stack_of_cards << Card.new("A", "Spades", 1)
stack_of_cards << Card.new("2", "Spades", 2)
stack_of_cards << Card.new("3", "Spades", 3)
...

这是我的卡片类:

class Card

  attr_accessor :number, :suit, :value

  def initialize(number, suit, value)
    @number = number
    @suit = suit
    @value = value
  end

  def to_s
    "#{@number} of #{@suit}"
  end
end

我想打乱这个数组/哈希中的元素(这叫什么?:S)

有什么建议吗?

【问题讨论】:

  • 我可以想象你跳过了 Struct,但是当你有时间的时候,看看它。

标签: ruby shuffle


【解决方案1】:
stack_of_cards.shuffle

它是一个数组,有关详细信息,请参阅http://www.ruby-doc.org/core-1.8.7/classes/Array.html

我已经编写了functional 表单,它返回一个新数组,它是新的被洗牌的数组。您可以改为使用:

stack_of_cards.shuffle!

...就地洗牌。

【讨论】:

  • 字? Array 类上居然有 shuffle 方法?耶稣!
  • 这不会修改数组。供参考。 :P 忽略,你编辑了你的答案...
  • 查看更新日志,#shuffle 似乎是在 2006 年 8 月的最后一天添加的,我认为这将导致它首次出现在 1.8.6 中。对于各种 Ruby 书籍的某些版本来说,这肯定为时已晚。
  • 为了更有趣,还有 Array.sample ,它从你的数组中返回一个随机元素。如果需要 3 个随机元素,请使用 Array.sample(3)。
  • “对于各种 Ruby 书籍的某些版本来说,这肯定为时已晚”。明确地。对于出版商来说,Ruby 似乎是移动最快的目标之一。我什至不想谈论寻找好的 Rails 书籍,因为它们在出版时已经过时了。 :-)
【解决方案2】:

如果你想洗牌,你可以使用这样的东西:

class Hash
  def shuffle
    Hash[self.to_a.sample(self.length)]
  end

  def shuffle!
    self.replace(self.shuffle)
  end
end

我已经发布了这个答案,因为如果我搜索“ruby shuffle hash”,我总是会找到这个问题。

【讨论】:

    【解决方案3】:

    除了using the shuffle method,还可以使用排序方式:

    array.sort {|a, b| rand <=> rand }
    

    如果您使用的是未实现shuffle 的旧版Ruby,这可能很有用。与shuffle! 一样,您可以使用sort! 处理现有数组。

    【讨论】:

    • 那行不通。 [1, 2, 3].sort { rand.round } 总是返回 [1, 2, 3][3, 2, 1]。正确的方式应该是[1, 2, 3].sort { rand &lt;=&gt; rand },或者[1, 2, 3].sort_by { rand }(如果可以使用shuffle就避免)。
    • 如果您知道的话,也可以提及 HASH...以防万一
    • 这是一种非常无效的洗牌方式。排序算法不会将每个元素与每个元素进行比较。它们隐含地对推论进行编码,例如“如果我比较 A 小于 B,并且 B 小于 C,那么我可以在不检查的情况下推断 A 小于 C”。结果严重偏斜,如此处所述(在 ObjC 中,但同样适用)cocoawithlove.com/2010/06/… 我要求您删除或更改此答案
    【解决方案4】:

    如果您想发疯并编写自己的就地 shuffle 方法,您可以这样做。

     def shuffle_me(array)
       (array.size-1).downto(1) do |i|
         j = rand(i+1)
         array[i], array[j] = array[j], array[i]
       end
    
       array
     end 
    

    【讨论】:

    • 为什么是rand(array.size-1) 而不是rand(array.size)rand 不包括在内,因此例如 rand(5) 将输出 0 - 4 之间的数字。
    • 是的,我之前的实现实际上存在一些问题。我修改了上述方法以反映 Knuth Shuffle 算法。 en.wikipedia.org/wiki/…
    【解决方案5】:

    对于数组:

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

    对于哈希:

    Hash[*hash.to_a.shuffle.flatten]
    Hash[*{a: 1, b: 2, c: 3}.to_a.shuffle.flatten(1)]
    #=> {:b=>2, :c=>3, :a=>1}
    #=> {:c=>3, :a=>1, :b=>2}
    #=> {:a=>1, :b=>2, :c=>3}
    # Also works for hashes containing arrays
    Hash[*{a: [1, 2], b: [2, 3], c: [3, 4]}.to_a.shuffle.flatten(1)]
    #=> {:b=>2, :c=>3, :a=>1}
    #=> {:c=>[3, 4], :a=>[1, 2], :b=>[2, 3]}
    

    【讨论】:

      【解决方案6】:

      老问题,但也许对其他人有帮助。我用它制作了一个纸牌游戏,这是@davissp14 写的,叫做“Fisher-Yates 算法”

      module FisherYates
      
        def self.shuffle(numbers)
          n = numbers.length
          while n > 0 
            x = rand(n-=1)
            numbers[x], numbers[n] = numbers[n], numbers[x]
          end
          return numbers
        end
      
      end 
      

      现在您可以将其用作:

      numbers_array = [1,2,3,4,5,6,7,8,9]
      asnwer = FisherYates.shuffle(numbers_array)
      return answer.inspect
      

      https://dev.to/linuxander/fisher-yates-shuffle-with-ruby-1p7h

      【讨论】:

        【解决方案7】:

        如果你想打乱一个哈希,但又不想重载 Hash 类,你可以使用 sort 函数,然后使用 to_h 函数(Ruby 2.1+)将其转换回哈希:

        a = {"a" => 1, "b" => 2, "c" => 3}
        puts a.inspect
        a = a.sort {|a, b| rand <=> rand }.to_h
        puts a.inspect
        

        【讨论】:

          【解决方案8】:

          对于数组:

          array.shuffle

          对于哈希:

          hash.sort_by{ rand() }

          【讨论】:

            猜你喜欢
            • 2010-12-21
            • 2011-05-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-08-26
            • 2014-07-24
            相关资源
            最近更新 更多