将行转为列(对我可以使用的方法有限制)

Transposing rows to columns (with limitations on what methods I can use)

我正在做一道练习题,问题是将 Ruby 中的行转置为列。

我理解 while 循环是 Ruby 中的 "rookie-esque",但我认为他们更喜欢我使用基本方法和控制流程语句:whileeach, map.显然,我不能使用Array#transpose。他们想让我基本上从头开始写 Array#transpose

它一直告诉我:

undefined method `[]=' for nil:NilClass (NoMethodError)

这是我的代码:

def transpose(rows)
  idx1 = 0
  cols = []

  while idx1 < rows.count
    idx2 = 0
    while idx2 < rows[idx1].count
      cols[idx1][idx2] = rows[idx2][idx1]
      idx2 += 1
    end
    idx1 += 1
  end

  return cols
end

puts transpose(rows = [
  [0, 1, 2],
  [3, 4, 5],
  [6, 7, 8]
])

在你的外部 while 循环中,你需要使 cols[idx1] 成为一个空数组,否则在你的内部 while 循环中它是 nil:

while idx1 < rows.count
  cols[idx1] = []
  idx2 = 0
  while idx2 < rows[idx1].count
    # ...
  end
end

也许这会对你有所帮助:

def transpose(rows)
  idx1 = 0           # => 0
  cols = []          # => []

  while idx1 < rows.count                  # => true
    idx2 = 0                               # => 0
    while idx2 < rows[idx1].count          # => true
      cols[idx1][idx2] = rows[idx2][idx1]  # ~> NoMethodError: undefined method `[]=' for nil:NilClass
      idx2 += 1
    end
    idx1 += 1
  end

  return cols
end

puts transpose(rows = [
  [0, 1, 2],             # => [0, 1, 2]
  [3, 4, 5],             # => [3, 4, 5]
  [6, 7, 8]              # => [6, 7, 8]
])

# ~> NoMethodError
# ~> undefined method `[]=' for nil:NilClass

这是使用 "Seeing Is Believing" 在 Sublime Text 2 中创建的。

分解一下,这是你出错的地方:

cols = []   # => []
cols[0]     # => nil
cols[0][0]  # ~> NoMethodError: undefined method `[]' for nil:NilClass

您不能在 nil 上使用子索引。空数组中不存在第一个索引。

你可以使用 Array#new 和块来做到这一点:

Array.new(rows.size) { |i| Array.new(rows.size) { |j| rows[j][i] } } 
  #=> [[0, 3, 6], [1, 4, 7], [2, 5, 8]]

或者,您可以使用 class Matrix 中的方法,您需要:

require 'matrix'

这里有一个不使用Array#transpose的简单方法,虽然它可能不符合问题的精神:

Matrix[*rows].transpose.to_a
  #=> [[0, 3, 6], [1, 4, 7], [2, 5, 8]] 

但是,您可以这样做:

Matrix.build(rows.size) { |i,j| rows[j][i] }.to_a
  #=> [[0, 3, 6], [1, 4, 7], [2, 5, 8]] 

使用嵌套 Enumerable#maps 进行比较的另一种方法:

rows = [[0, 1, 2],
        [3, 4, 5],
        [6, 7, 8]]

def my_transpose(matrix)
  matrix.first.size.times.map { |column| matrix.map { |row| row[column] } }
end

my_transpose(rows)
# => [[0, 3, 6], [1, 4, 7], [2, 5, 8]]

my_transpose(my_transpose(rows))
# => [[0, 1, 2], [3, 4, 5], [6, 7, 8]]