更改代码的顺序会导致错误?

时间:2017-03-18 04:54:24

标签: ruby

     def stock_picker prices
        min_day , max_day , profit = 0 , 0 , 0
        i = 1
        while i < prices.length    
            (0...i).each do |day|
              if prices[i] - prices[day] > profit
                  min_day , max_day , profit = day , i , prices[i] - prices[day]
              end
                #i += 1
            end
            i += 1
        end

            return "[#{min_day}, #{max_day}]"
      end

        prices = [17,3,6,9,15,8,6,1,10]

        puts stock_picker prices

我的目标是实施一种方法#stock_picker,它接受一系列股票价格,每个假设日一个。它应该返回一天代表最佳购买日和最佳销售日。天数从0开始。

我的问题是,如果我删除第11行并将其写在第9行,为什么这段代码不起作用。然后会导致错误如下:

**PS C:\Users\dlim\mystuff> ruby stockpicker.rb
stockpicker.rb:8:in `block in stock_picker': undefined method `-' for nil:NilClass (NoMethodError)
        from stockpicker.rb:7:in `each'
        from stockpicker.rb:7:in `stock_picker'
        from stockpicker.rb:29:in `<main>'

2 个答案:

答案 0 :(得分:1)

您基本上是在尝试重写combinationmax_by

prices = [17, 3, 6, 9, 15, 8, 6, 1, 10]
days = (0...prices.size).to_a
p days.combination(2).max_by { |day1, day2| prices[day2] - prices[day1] }
# => [1,4]

如果您想要两天和相应的价格:

[17,3,6,9,15,8,6,1,10].each.with_index.to_a.
                       combination(2).max_by{|(buy, day1), (sell, day2)|
                         sell-buy
                       }
# => [[3, 1], [15, 4]]

答案 1 :(得分:0)

这种情况发生在哪里?

您的错误

stockpicker.rb:8:in `block in stock_picker': undefined method `-' for nil:NilClass (NoMethodError)
   from stockpicker.rb:7:in `each'
   from stockpicker.rb:7:in `stock_picker'
   from stockpicker.rb:29:in `<main>'

发生在第8行

if prices[i] - prices[day] > profit

prices[i]i = 9返回prices时尝试访问nil时, 它不响应减号-运算符。

为什么会发生这种情况?

你是一个循环中的循环

(0...i).each do |day|
  if prices[i] - prices[day] > profit
      min_day , max_day , profit = day , i , prices[i] - prices[day]
  end
  #i += 1
end

在这里增加i索引计数器变量并没有多大意义,因为 day已经迭代了范围(0...i)和中的值 在此循环中增加i意味着它会比较prices中的每个值 数组一次,对应day内部数组中的下一个prices值 将只包含prices的前三个值(表示值为 prices数组的结尾,例如110永远不会被比较 另一个); e.g。

i = 1
prices = [17,3,6,9,15,8,6,1,10]

# iteration 0
if prices[i] - prices[day] > profit
#          3 - 17 > 0 # => false


# iteration 1
i += 1 # => 2
day # => 0

if prices[i] - prices[day] > profit
#          6 - 17 > 0 # => false

i += 1 # => 3
day # => 1


# iteration 2
if prices[i] - prices[day] > profit
#          9 - 3 > 0 # => true
min_day, max_day, profit = 1, 3, 6

i += 1 # => 4
day # => 0


# iteration 3
if prices[i] - prices[day] > profit
#          15 - 17 > 0 # => false

i += 1 # => 5
day # => 1


# iteration 4
if prices[i] - prices[day] > profit
#          8 - 3 > 0 # => true

min_day, max_day, profit = 1, 5, 5
i += 1 # => 6
day # => 2


# iteration 5
if prices[i] - prices[day] > profit
#          6 - 6 > 0 # => false

i += 1 # => 7
day # => 3


# iteration 6
if prices[i] - prices[day] > profit
#          1 - 9 > 0 # => false

i += 1 # => 8
day # => 0


# iteration 7
if prices[i] - prices[day] > profit
#         10 - 17 > 0 # => false

i += 1 # => 9
day # => 1


# iteration 8
if prices[i] - prices[day] > profit
#        nil - 3 > 0 # => NoMethodError

在第8次迭代时,外部循环导致了越界错误 使用prices[i]访问价格数组,但仍在迭代中 第二次循环,其范围为(0...7),是在第5次迭代后设置的,所以 它没有达到你的while循环的转义子句/表达式 while i < prices.length

可能的解决方案:

您可以保留您的工作解决方案,也可以通过使用来简化代码 另一个Range作为外循环

(1...prices.length).each do |i|
  # ...
end

而不是在while循环中增加索引计数器变量

i = 1
while i < prices.length
  # ...
  i +=1
end

看起来像这样

def stock_picker prices
  min_day , max_day , profit = 0 , 0 , 0
  (1...prices.length).each do |i|
    (0...i).each do |day|
      if prices[i] - prices[day] > profit
        min_day , max_day , profit = day , i , prices[i] - prices[day]
      end
    end
  end

  return "[#{min_day}, #{max_day}]"
end

prices = [17,3,6,9,15,8,6,1,10]

puts stock_picker prices

根据您的要求,它会迭代以下几天

[i, day]
# => [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0],
#    [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1],
#    [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2],
#    [4, 3], [5, 3], [6, 3], [7, 3], [8, 3],
#    [5, 4], [6, 4], [7, 4], [8, 4],
#    [6, 5], [7, 5], [8, 5],
#    [7, 6], [8, 6],
#    [8, 7]

<强>更新

您还可以使用Ruby Array combination method

再次简化它
(0...prices.length).to_a.combination(2)

生成相同的唯一且不重复的天数,以迭代隐含的范围,这看起来像这样

def stock_picker prices
  min_day , max_day , profit = 0 , 0 , 0
  (0...prices.length).to_a.combination(2).each do |day, i|
    if prices[i] - prices[day] > profit
      min_day , max_day , profit = day , i , prices[i] - prices[day]
    end
  end

  return "[#{min_day}, #{max_day}]"
end

prices = [17,3,6,9,15,8,6,1,10]

puts stock_picker prices

|day, i|将访问组合数组中日期索引对数组中的第一个和第二个变量,同时重用您已使用的现有变量名称。