关于 Ruby 中数组的简单问题 - 创建时和使用数组数据时的额外数组元素

Simply Question on Arrays in Ruby - Extra Array Element Upon Creation and When Working With Array Data

# For example, the base [1, 4, 6] gives us the following pyramid
#     15
#   5   10
# 1   4    6

def pyramid_sum(base)
  pyramid = [base]
  new_level = []
  prev_level = []
  base.length.times { |x|
    prev_level = pyramid[0]
    new_level = build(prev_level)
    pyramid.unshift(new_level)
  } 
  return pyramid
end

def build(level)
  new_level = []
  level.each_with_index { |num, index|
    if index < level.length-1
      new_level <<level[index] + level[index+1]
    end
  }
  return new_level
end

print pyramid_sum([1, 4, 6]) #=> [[15], [5, 10], [1, 4, 6]]
puts

print pyramid_sum([3, 7, 2, 11]) #=> [[41], [19, 22], [10, 9, 13], [3, 7, 2, 11]]
puts

输出: ** [[], [15], [5, 10], [1, 4, 6]] [[], [41], [19, 22], [10, 9, 13], [3, 7, 2, 11]] **

为什么二维数组前面总是多出一个[](空数组)?我在 Ruby 中的数组结果中多次看到这种情况,虽然它很简单,但我似乎无法弄清楚为什么那个额外烦人的数组总是存在?我知道这很简单,如果有必要,我可能会删除这个问题,但为什么我的数组前面有一个额外的数组元素?似乎只是创建一个数组,它总是有一个额外的元素,我不能“真正地”修改它,因为 Ruby 中的所有内容都是一个对象。

之所以在开始时得到额外的空数组,是因为您告诉 pyramid_sum 函数向基础添加 base.length 个更多级别。

以这种方式组成的金字塔的层数与其底部的项目数相同。

所以这意味着当你写 base.length.times { |x| ... } 时,你实际上是在说你将在基础之上添加 base.length 新的 extra 级别等级.

对于您的第一个示例,[1, 4, 6],这意味着您说在此基础层之上,您将再添加三层:

  • 首先,您将分段总结基础层,添加[5, 10]
  • 其次,您将分部分总结新的第二层,添加[15]
  • 最后,您将尝试总结第三层的部分,这将导致[]

原因是当您尝试对第三层求和时,其中没有足够的项目来添加下一层的任意两个数字。因此,您最终将添加未修改的空 new_layer = []

如果你想解决这个问题,你可以 运行 迭代 (base.length - 1).times,或者你可以添加一个 if 语句作为保护,不添加任何生成的空层:

new_level = build(prev_layer)
if new_level.length > 0
  pyramid.unshift(new_level)
end

作为第一步,我稍微重新格式化了您的代码并删除了一些无用的代码。 (例如,在 pyramid_sum 中对 new_levelprev_level 的赋值是无用的,因为它们会立即在块中重新赋值。)

def pyramid_sum(base)
  pyramid = [base]

  base.length.times do
    prev_level = pyramid.first
    new_level = build(prev_level)
    pyramid.unshift(new_level)
  end

  pyramid
end

def build(level)
  new_level = []

  level.each_index do |index|
    if index < level.length - 1
      new_level << level[index] + level[index + 1]
    end
  end

  new_level
end

删除那些无用的赋值后,产生问题的两行就在彼此的下面,问题几乎已经跳出来了:

  • 金字塔的高度应始终与底部的宽度相同。
  • 你预先初始化结果变量,将原始基作为金字塔的第一层。
  • 但是然后你重复 build 方法 base.length 次,即 除了 你已经预初始化的一层,你 添加另一个base.length关卡……结果,你最终得到的关卡太多了:你根据需要构建了尽可能多的关卡,但你已经在结果中加入了另一个关卡。

解决方法很简单:迭代 base.length - 1 次:

def pyramid_sum(base)
  pyramid = [base]

  (base.length-1).times do
    prev_level = pyramid.first
    new_level = build(prev_level)
    pyramid.unshift(new_level)
  end

  pyramid
end

def build(level)
  new_level = []

  level.each_index do |index|
    if index < level.length - 1
      new_level << level[index] + level[index + 1]
    end
  end

  new_level
end

请注意,此问题几乎 尖叫 递归。像这样:

def pyramid_sum(*base) = pyramid_rec([base]).reverse

def pyramid_rec(pyramid)
  return pyramid if pyramid.last.size <= 1

  pyramid_rec(pyramid << pyramid.last.each_cons(2).map(&:sum))
end

puts pyramid_sum(1, 4, 6)
puts pyramid_sum(3, 7, 2, 11)