【问题标题】:Ruby: Continue looping through an array of fixed length, adding 1 to each element for each iterationRuby:继续循环遍历一个固定长度的数组,每次迭代的每个元素都加 1
【发布时间】:2020-07-07 15:35:10
【问题描述】:
def baubles_on_tree(ornaments, branches)
  counter = 0
  decorations = []
  
  
  puts ornaments, branches
  # Evenly distribute ornaments across branches
  
  # if there are no branches, return string
  if branches == 0
    return "Grandma, we will have to buy a Christmas tree first!"
  end
  
  puts "The number of ornaments (#{ornaments}) divided by branches (#{branches}) equal " + ((ornaments / branches).to_f).to_s
  
  # add 1 to the decorations array while counter <= ornaments.
  # ensure decoration.length maxes out at branches
  
    while counter <= ornaments

      # Add 1 to counter until it reaches the number of ornaments
      counter += 1
      #puts decorations.length
      
      # Push 1 to the decorations array for each iteration
      decorations << 1
      
      # if the decorations array length equals the number of branches,
      # stop creating new indices and instead add 1 to each array element
      if decorations.length == branches 
        print decorations.length
         
        decorations.map! {|n| n + 1 }
      end
      
    end
    print decorations
  
end

Test.describe("Here are some test cases") do
  Test.assert_equals(baubles_on_tree(5,5),[1,1,1,1,1])
  Test.assert_equals(baubles_on_tree(5,0),"Grandma, we will have to buy a Christmas tree first!")
  Test.assert_equals(baubles_on_tree(6,5),[2,1,1,1,1])
  Test.assert_equals(baubles_on_tree(50,9),[6,6,6,6,6,5,5,5,5])
  Test.assert_equals(baubles_on_tree(0,10),[0,0,0,0,0,0,0,0,0,0])
end

问题:大家好。我很难找到在 if decors.length == branches 块中使用的正确语法。目前,

decorations.map! {|n| n + 1 }

在每次迭代的装饰数组中的每个元素上加 1。相反,我想将 1 添加到单个数组元素(从左到右),直到计数器等于装饰品的数量。

目标:bables_on_tree 函数的最终目标是将装饰品均匀地分布在圣诞树的所有分支上。如果饰品=7,分支=5,则返回的数组为[2,2,1,1,1]

感谢您的指导!

【问题讨论】:

    标签: arrays ruby conditional-statements


    【解决方案1】:

    您的方法可以大大简化。

    简单的方法

    1 def baubles_on_tree(ornaments, branches)
    2   return "Grandma, we will have to buy a Christmas tree first!" if branches.zero?
    3   tree = Array.new(branches) { |e| ornaments / branches }
    4   (ornaments % branches).times { |i| tree[i] += 1 }
    5   tree
    6 end
    

    您正在考虑如何作为人类来做这件事,一次将装饰品贴在树上。你正在使用循环和其他东西来模拟这种行为。有时重要的是退后一步,看看你想要的结果,然后想出最有效的方法来获得这个结果。

    如果我们这样做,我们可以跳过很多循环逻辑:

    1. ornaments 除以branches
    2. 将该值分配给大小为branches 的数组的每个元素。
    3. 遍历其余的装饰品,在每个分支上添加一个,直到我们用完为止。

    这将迭代(循环)的数量减少到不均匀分布在分支上的任何东西。

    要实现这一点,我们需要两行代码。

    1. 在第 3 行,我们在上面的第 1 步和第 2 步中创建了数组。 Array.new(branches) 将创建一个元素数量与branches 相同的数组。该块告诉Array.new 为每个元素分配什么值。在这种情况下,我们分配ornaments / branches
    2. 在第 4 行:ornaments % branchesornaments / branches 的剩余部分。因此,这一行执行传递给#times 方法ornaments % branches 次的块,将0 通过ornaments % branches - 1 一个接一个地传递给i。我们将1 添加到这些索引处的每个元素。

    申请测试baubles_on_tree(50,9):

    1. 第 3 行创建一个包含九个元素的数组。 50 / 95,所以在那一行之后,tree == [5, 5, 5, 5, 5, 5, 5, 5, 5]
    2. 然后第 4 行将1 添加到前五个元素,因为50 % 95,我们得到tree == [6, 6, 6, 6, 6, 5, 5, 5, 5]

    在第 5 行,我们将 tree 返回给调用者,而 Bob 是你的叔叔。 :)

    困难的方法,解释你哪里出错了

    回答您的具体问题:您之所以会得到一大堆 1,开头有几个 2,而不是您正在寻找的值,是因为您为每个装饰品将1 推送到您的数组一次,而不是为每个装饰品将1 添加到适当的数组元素一次。这就是decorations &lt;&lt; 1 所做的。这样做 50 次,你会得到一个包含 50 个1 的数组。

    因此,您会得到一个大小为 ornaments 的数组,每个元素中都有一个 1。在循环的一次迭代中,如果数组 (decorations) 的大小与 branches 相同,则将 1 添加到数组中当前大小的所有值中,然后继续使用 1直到你的饰品用完为止。

    所以你得到一个大小为ornaments 的数组,在第一个branches 元素中有一个2,在其他每个元素中都有一个1

    要做到这一点,你必须循环 ornaments(你做对了),但在装饰循环中,你必须循环 branches 并将 1 添加到每个元素(并不断增加在ornament 循环计数器之外,因为每次循环通过内部循环时都会用完一个装饰品)。您还必须弄清楚如何开始,以及如何确保在饰品用完时及时停下来。

    类似这样的东西(通过你的测试):

    def baubles_on_tree(ornaments, branches)
      return "Grandma, we will have to buy a Christmas tree first!" if branches.zero?
      decorations = []
    
      # First, put the right amount of zeros in the array (ensure that
      # decorations.size == branches, and each element has a 0 in it)
      counter = 0
      while counter < branches
        decorations << 0
        counter += 1
      end
    
      # Then, loop through ornaments
      counter = 0
      while counter < ornaments
    
        # Inside the ornaments loop, loop through branches. We have to keep track
        # of the outer loop here, too, because if we run out of ornaments before
        # we're done putting an ornament on each branch, we want to quit right away.
        counter2 = 0
        while counter2 < branches && counter < ornaments
    
          # ADD 1, don't push 1 (don't use <<)
          decorations[counter2] += 1 
    
          # increment both counters; since we're putting an ornament on each branch,
          # we have to keep the outer loop going while we loop through the inner one
          counter2 += 1
          counter += 1
        end
      end
      decorations # Return the array
    end
    

    虽然只使用 while 循环可能是一个有趣的练习,但只需做一些算术并获得相同的结果就容易多了。

    【讨论】:

    • 出色的评论,鲍勃,感谢您的帮助(再次!)。我知道有一种更有效的方法可以解决这个问题,但我不熟悉“times”方法。再次感谢您将其分解!
    • @MrSandman98765 哦,没错,你是“#each` 与 #map 的人。:) 非常欢迎你。#times 是“Ruby 惯用”版本for 循环。Ruby 有一个for 循环,但标准约定是使用#times
    【解决方案2】:

    这行得通。

    注意:看来你是 Ruby 的初学者,所以我尽量让我的代码尽可能简单:)

    def create_arrays(nb_element, nb_arrays)
      arrays = []
      i = 0
      loop do
        arrays[i] = Array.new(nb_element)
        i += 1
        if i == nb_arrays
          break       # this will cause execution to exit the loop
        end
      end
      return arrays
    end
    
    def get_nb_arrays(ornaments, branches)
      if ornaments == 0
        return branches
      else
        return ornaments/branches + ornaments % branches
      end
    end
    
    def baubles_on_tree(ornaments, branches)
      if branches == 0
        return "Grandma, we will have to buy a Christmas tree first!"
      end
    
      arrays = create_arrays(branches, get_nb_arrays(ornaments, branches))
      n = ornaments
    
      i = 0
      while i < arrays.length
        ar = arrays[i]
    
        j = 0
        while j < ar.length
          if n > 0
            ar[j] = 1
          else 
            ar[j] = 0
          end
          n -= 1
          j += 1
        end
        i += 1
      end
      return arrays.transpose.map {|x| x.reduce(:+)}
    end
    

    祝你好运!

    【讨论】:

    • 你得到了它的工作,这是一件好事。但是代码仍然可以比这更简单,即使您确实使用了while 循环。 :) 看我的回答。
    • 感谢 BinaryMan 的解决方案。我知道你说过你故意让你的代码冗长以保持简单,但我实际上发现它比上面 Bob 的重构解决方案更难遵循。不过,我发现分解你的代码是有益的,我感谢你的努力。
    • @BinaryMan 我认为您可能错过了在j 循环内增加i 的想法,因此不得不通过跟踪n 来稍微折磨您的代码分别地。如果我没有半睡半醒,并且每次内循环增加时,我都会看到一个装饰品从盒子中弹出的景象,我不能说这是我会想到的。
    猜你喜欢
    • 2015-07-30
    • 2019-01-20
    • 1970-01-01
    • 2023-03-25
    • 2012-01-04
    • 2015-02-24
    • 2017-10-22
    • 2014-12-08
    • 1970-01-01
    相关资源
    最近更新 更多