从数组中检索列的有效方法是什么?

时间:2015-01-14 17:04:48

标签: javascript ruby arrays

任何语言的示例都会有所帮助,但最终我将使用Ruby或JavaScript / CoffeeScript。

我有一个像素值数组。例如,我有一个表示5x5图像像素的数组。

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

图像就像:

1 2 3 4 5
6 7 8 9 0
1 2 3 4 5
6 7 8 9 0
1 2 3 4 5

我已经有了获取行的方法。但我想要一种方法来检索索引的列。

假设我在Ruby中有一个方法:

class Array
  def column(index)
    ...
  end
end

我想要以下结果:

image.column(0) #=> [1,6,1,6,1]
image.column(3) #=> [4,9,4,9,4]

编辑:感谢所有提供帮助的人。这就是我的目的:

def column index
  output = []
  i = 0
  while i < @height
    output << pixel(index + (i * @width))
    i += 1
  end
  output
end

Pixel是另一种方法,它在给定索引的情况下从RGBA值数组中返回平均值。

这就足够了,我可以放心地假设图像中的每一行/每列都是正确的大小。我还想让这个过程相当简单,因为我可能会把它变成一个使用类型钳位数组的CoffeeScript应用程序(出于性能原因以及canvas数据是Uint8ClampedArray的事实),在这种情况下,输出的值将是Uint8ClampedArray和我将使用索引而不是push,因为Uint8ClampedArray不支持/不支持push / pop / shift / unshift。

4 个答案:

答案 0 :(得分:4)

许多其他答案适用于您的问题所指定的正好为5x5的图像,但如果这不是隐含的,我会为此构建一个类,如:

class ImageMap
  attr_reader :image
  def initialize(image,columns=nil)
    @image = image.each_slice(columns ||= Math.sqrt(image.size)).to_a 
  end
  def columns
    @image.first.size
  end
  def rows
    @image.size
  end
  def column(n)
    @image.map{|a| a[n]}
  end
  def row(n)
    [@image[n]].concat([nil] * columns).take(columns).flatten
  end
  def cell(column,row)
    column(column)[row]
  end
  def print
    @image.each {|a| puts a.join}
  end
end

这将处理所有图像,并允许您也设置预期列的数量。如果没有列期望,那么它会尝试使其成为正方形。

<强>方形

image = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5]
im = ImageMap.new(image)
im.column(0)
#=> [1, 6, 1, 6, 1]
im.column(3)
#=> [4, 9, 4, 9, 4]
im.row(0)
#=> [1, 2, 3, 4, 5]
im.cell(4,2)
#=> 5

非正方

image = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5]
im = ImageMap.new(image,4)
im.column(0)
#=> [1, 5, 9, 3, 7, 1, 5]
im.columns
#=> 4
im.rows
#=> 7

显然,这可以使用一些处理越界值,但你应该能够处理它。不存在的行/列的示例:

im.column(7)
#=> [nil, nil, nil, nil, nil]
im.row(7)
#=> [nil, nil, nil, nil, nil]
im.cell(7,2)
#=> nil

另请注意,如果它不是方形,它仍将起作用,例如。

image = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,4] # added a 4
im = ImageMap.new(image)
im.column(0)
#=> [1, 6, 1, 6, 1, 4]
im.column(1)
#=> [2, 7, 2, 7, 2, nil]
im.image
#=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 0], [1, 2, 3, 4, 5], [6, 7, 8, 9, 0], [1, 2, 3, 4, 5], [4]]

根据OP当前解决方案进行更新 这种方法应该预先形成相同的功能,并且有点像rubyesque

def column index
  (0...@height).map { |i| pixel(index + (i * @width)) }
end

答案 1 :(得分:3)

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

def column(image, n, row_length)
  (n..image.length).step(row_length).map{|i| image[i]}
end

column(image, 3, 5) # => [4, 9, 4, 9, 4]

答案 2 :(得分:3)

您可以考虑创建一个单独的类,而不是在类Array中创建新方法。我假设image的大小是多行的倍数 - 考虑到示例并且我们正在讨论像素 - 但如果丢弃该假设,代码显然可以改变。

感谢@SergioTulentsev和@engineersmnky提出的建议(见评论),我已经实施了。

<强>代码

class Array2D
  def initialize(arr, ncols)
    raise ArgumentError, "ncols must be positive" if ncols < 1
    raise ArgumentError,
      "arr.size must a multiple of ncols" unless (arr.size % ncols).zero?
    @arr   = arr
    @ncols = ncols
    @nrows = arr.size/ncols
  end

  def [](r,c)           @arr[r*@ncols+c]               end
  def row(r)            @arr[r*@ncols, @ncols]         end
  def rows_at(*indices) indices.map { |i| row(i) }     end
  def col(c)            @nrows.times.map { |r,a| self[r,c] } end
  def cols_at(*indices) indices.map { |i,a| col(i) }   end
  def array()           rows_at(*0...@nrows)           end
  def transpose()       cols_at(*0..@ncols)            end
  alias :to_s :array
end

Array2D.instance_methods(false)
  #=> [:[], :row, :rows_at, :col, :cols_at, :array, :transpose, :to_s]

请注意,方法selfself[r,c]需要col。如果没有self[1,2]将返回一个数组。

示例

image = [1,2,3,4,5,6,7,8,9,0,11,12,13,14,15,16,17,18,19,10,21,22,23,24,25]

image2D = Array2D.new(image, 5)

image2D.array
  #=> [[ 1,  2,  3,  4,  5],
  #    [ 6,  7,  8,  9,  0],
  #    [11, 12, 13, 14, 15],
  #    [16, 17, 18, 19, 10],
  #    [21, 22, 23, 24, 25]]
image2D[1,3]
  #=> 9 
image2D.row(1)
  #=> [6, 7, 8, 9, 0] 
image2D.rows_at(1,3)
  #=> [[6, 7, 8, 9, 0], [16, 17, 18, 19, 10]]
image2D.col(1)
  #=> [2, 7, 12, 17, 22] 
image2D.cols_at(1,3)
  #=> [[2, 7, 12, 17, 22],
  #    [4, 9, 14, 19, 24]]
image2D.transpose
  #=> [[1, 6, 11, 16, 21],
  #    [2, 7, 12, 17, 22],
  #    [3, 8, 13, 18, 23],
  #    [4, 9, 14, 19, 24],
  #    [5, 0, 15, 10, 25]] 

答案 3 :(得分:1)

def column(index)
    (0...5).map{|i|image[i*5+index]}
end