Ruby中的布尔数组更改

时间:2017-09-20 16:13:38

标签: arrays ruby boolean iteration

我遇到了这个代码问题 - 我需要遍历一系列布尔值100次。说明:

戴着帽子的猫

你有100只猫。你的规则很简单:每当你访问一只猫时,你都会切换它的帽子状态(如果它已经有一顶帽子,你将其删除......如果它没有帽子,你可以将它打开)。所有的猫都开始无帽了。你循环100轮拜访猫。在第一轮,你会看到每只猫。在第二轮,你访问每一只猫。在第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]

3 个答案:

答案 0 :(得分:3)

欢迎来到红宝石。有人很好地解释了代码的问题。我想我会尽快给你一个红宝石物体的力量。

让我们从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 

很棒我们所有的Cat已经通过并切换现在让我们计算带帽子的人

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

这通常会更加惯用地表达为cats.count(&: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 Object是令人惊叹的,并且可以用于非常简单的简单代码。 Full Example

答案 1 :(得分:1)

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. 的指针
  3. 使用新指针
  4. 覆盖块局部变量cat

    这个新指针决不会在你的cats数组中结束!

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

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

答案 2 :(得分:0)

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

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