如何在不更改原始数组的情况下复制和删除数组?

时间:2017-06-05 20:02:45

标签: arrays ruby debugging math

我的目标是编写一个执行以下操作的方法trickysum(n)

该方法采用数字1到n的范围。然后,该方法在该范围内找到满足棘手资格的数字对:该对数字的乘积必须等于该范围内所有数字的总和,不包括该对。该方法然后返回符合此资格的所有数字对。这是期望:

  trickysum(26) 
  #=>[(15, 21), (21, 15)]

这是我到目前为止的代码:

def trickysum(n)

result = []
arr = (1..n).to_a

0.upto(arr.length - 1) do |x|

  0.upto(arr.length - 1) do |y|

    prod = arr[x] * arr[y]
    #I create a new array to delete from to not affect the original 
    #array. Would also love an easier way to do this :)
    new_arr = arr  
    new_arr.delete(new_arr[x])
    new_arr.delete(new_arr[y])
    sum = new_arr.inject(:+)
    if sum == prod
      result << "(#{arr[x]},#{arr[y]})"
    end
  end
end

result 

end

我一遍又一遍地查看这段代码,无法弄清楚为什么我收到以下错误:

nil can't be coerced into Fixnum
(repl):7:in `*'
(repl):7:in `block (2 levels) in trickysum'
(repl):6:in `upto'
(repl):6:in `block in trickysum'
(repl):5:in `upto'
(repl):5:in `trickysum'
(repl):20:in `<main>'

我哪里错了?

1 个答案:

答案 0 :(得分:3)

替换:

new_arr = arr

使用:

new_arr = arr.dup

这里发生的是您创建了arr变量的浅拷贝。如果没有明确重复该值,new_arrarr共享内存中的相同位置。

因此,当您致电new_arr.delete(new_arr[x])new_arr.delete(new_arr[y])时,您不仅会改变数组,还会改变数组

这意味着arr的长度变短,因此您的外部循环超出了其最终值,您得到nil;因此错误。

话虽如此,我会完全不同地编写这种方法,这可以避免这种微妙的错误:

def trickysum(n)
  sum = (1..n).inject(:+)
  (1..n).combination(2).select do |a, b|
    (a * b) + a + b == sum
  end
end

Ruby是非常富有表现力的语言。如果你发现自己在循环中循环,声明临时变量并附加到一组结果......那么可能是一个更优雅的解决方案:)