【问题标题】:Boolean Array change in RubyRuby 中的布尔数组更改
【发布时间】:2023-03-22 09:36:01
【问题描述】:

我被这个代码问题困住了——我需要遍历一个布尔数组 100 次。说明:

戴帽子的猫

你有 100 只猫。你的规则很简单:每当你拜访一只猫时,你切换它的帽子状态(如果它已经有一顶帽子,你把它拿掉。如果它没有帽子,你戴上一顶)。所有的猫都开始不戴帽子。您循环 100 轮来访的猫。在第一轮,你拜访每只猫。在第二轮中,你拜访了其他所有的猫。在第 n 轮中,您访问每 n 只猫......直到第 100 轮,您只访问第 100 只猫。在 100 轮结束时,哪些猫有帽子?

从 JS 开始接触 Ruby 并坚持如何实现这一点。我认为我的逻辑是正确的,我只是无法改变数组中布尔值的值。

非常感谢任何建议!

谢谢

def cats_in_hats

 cats = []

 i = 0
 while i< 100
 cats << false 
 i = i + 1 
 end 

 puts cats 


 round = 1;

 while round < 10

  # 
  cats = cats.each_with_index do |cat, idx|
    if idx % round == 0
      puts "toggle index #{idx} divisible by round #{round}"
      cat = !cat
      puts cat 
    end
  end

  round = round + 1 

 end 

puts cats 

end

puts "------Cats in Hats------"
puts cats_in_hats == [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

【问题讨论】:

    标签: arrays ruby boolean iteration


    【解决方案1】:

    欢迎来到红宝石。有人很好地解释了您的代码存在什么问题。我想我会让你快速了解一下 ruby​​ 中对象的力量。

    让我们从Cat 开始。它能做什么?嗯:

    • 可以戴帽子
    • 一开始不戴帽子
    • 它可以戴上和脱下帽子

    好的,让我们为此创建一个Object

    class Cat
      def initialize
        @hat = false # start out without a hat
      end
      def toggle_hat
        !@hat   # in case you just want to tip your hat in salutation to JörgWMittag
      end
      def toggle_hat!
        @hat = toggle_hat # @hat equals not(@hat) e.g. @hat = not(true) to take off the hat
      end
      def has_hat?
        @hat # does it have a hat true or false
      end
    end
    

    完美有一个Cat。现在让我们来看看这个问题。

    我们需要遍历 100 个cats。好的

    cats = Array.new(100) { Cat.new }
    

    现在我们有 100 只猫。让我们开始循环

    #loop from 1 up to 100 providing the loop number (n)
    1.upto(100).each do |n| 
      # for each n we skip over the preceding n and step by n
      (n..100).step(n) do |idx| 
        # pick the appropriate cat (ruby indexes start at 0) 
        # toggle his hat
        cats[idx - 1].toggle_hat!
      end
    end 
    

    太好了,我们所有的Cats 都已经循环播放并切换了,现在让我们数数那些戴着帽子的人

    # will count each cat where has_hat? is true
    cats.count {|cat| cat.has_hat? }
    #=> 10 
    

    这通常更习惯地表达为cats.count(&amp;:has_hat?)。这使用了 ruby​​ 的 Symbol#to_proc 糖,意味着在每个元素上调用 has_hat? 方法,如上面更明确地显示的那样。

    我们也可以收集它们

    cats.map.with_index {|cat,idx| idx + 1 if cat.has_hat? }.compact
    #=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
    

    Tada Objects 非常棒,可以编写出可读性极强的简单代码。 Full Example

    【讨论】:

    • 不要忘记 cats.count(&amp;:has_hat?) 是相同的简写。
    • @tadman 我会,但是 "New to Ruby from JS" 让我使用了更明确的块语法
    • 不是第一步,你有一个正确的想法,慢慢地打开它,但作为一个例子,说明 Ruby 如何真正缩小解决方案而不会使事情变得过于复杂。 cats.count(function(cat) { return cat.has_hat() }) 现在在 ES6 中是 cats.count(cat =&gt; cat.has_hat()),所以现在有很多相似之处。
    • @tadman 添加用于启发。虽然我发现人们真正的复杂之处是前面的&amp;: 符号
    • 一个更好的解释,很好!
    【解决方案2】:
    cats = cats.each_with_index do |cat, idx|
      # ...
      cat = !cat
    end
    

    这就是问题所在。 Ruby 中的所有对象都由指针表示在内存中,并且这些指针被复制以将对象传递给方法/块/等。因此,当您执行 each_with_index 时,Ruby 将每个元素的指针复制到您的块局部变量 cat 中。

    现在当你说cat = !cat 时,Ruby 就是这样做的

    1. cat指向的对象找到!方法并调用它。这将返回指向对象true 或对象false 的指针
    2. 用新指针覆盖块局部变量cat

    新指针绝不会出现在您的 cats 数组中!

    我可以想到两个主要的解决方案:

    1. 不存储布尔对象(不可变),而是将可变对象存储在cats 中。然后你可以在每个cat 上调用一个方法,告诉它改变它的状态(这就是@engineersmnky 的代码所做的)
    2. 不要使用块局部变量cat,而是告诉Ruby 将新指针直接复制到数组中:cats[idx] = !cat

    【讨论】:

      【解决方案3】:
      def cats_in_hats
        cats = []
      
        i = 0
        while i < 100
          cats << false 
          i = i + 1 
        end 
      
        p cats 
      
        round = 1;
      
        while round < 100
      
        cats = cats.collect!.with_index do |cat, idx|
          idx % round == 0 ? !cat : cat
        end
      
        round = round + 1 
      
        end 
      
        p cats 
      
      end
      
      puts "------Cats in Hats------"
      puts cats_in_hats
      

      您的初始代码的问题在于您从未在您的each_with_index 块中“做”任何事情。当您使用 cat = !cat 时,您只是在循环范围内更改该项目,而从未创建新数组。使用.collect!.with_indexmap/collect!.with_index(to get the index),您可以对数组中的每个项目执行操作,并在每次迭代时返回一个新数组。这类似于 JavaScript 的 map 函数的工作方式。如果您需要进一步解释,请告诉我。

      【讨论】:

        猜你喜欢
        • 2023-01-20
        • 2020-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-23
        • 2018-02-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多