Andrew
Andrew

Reputation: 43113

Ruby: combine array values

I have an array of arrays indicating coordinate values, like so:

cells = [ [0,0], [0,1] ]

Each array in the array is an X and Y value. So, if I want to shift this right, that would be X+1 on each cell. I could express this as a cell like so:

delta = [1,0]

Now, what I'd like to do is merge that value into each cell so that the X value of each cell is summed with the value of delta, so in this case the final output should be:

new_cells = [ [1,0], [1,1] ]

Here's the best I've been able to think of so far, it seems really heavy:

cells = [[0,0],[0,1]]
delta = [1,0]
cells.each do |cell|
  cell[0] = cell[0] + delta[0]
  cell[1] = cell[1] + delta[1]
end
# Now cells = [[1,0],[1,1]]

Is there a cleaner one-liner kind of method that would sum an array onto each array in a chain of arrays, or is the above the best solution to that problem?

Upvotes: 1

Views: 947

Answers (5)

Ken Bloom
Ken Bloom

Reputation: 58770

I think your best solution is to recognize that cells and deltas are a different data type that you could operate on more clearly if it weren't an array:

Cell = Struct.new(:x, :y) do 
  def + other
    Cell.new(self.x + other.x, self.y + other.y)
  end
end

# cells is some array of Cell objects
# delta is some Cell object

cells.map! {|cell| cell + delta}

Upvotes: 3

Gurpartap Singh
Gurpartap Singh

Reputation: 2764

Here's how you don't have to worry about matching the cell keys with delta's:

cells = cells.map {|cell| [cell,delta].transpose.map {|value| value.reduce(:+)}}

Step by step:

cells = cells.map { |cell|         # => [0,0]

  combined = [cell, delta]         # => [[0,0], [1,0]]

  transposed = combined.transpose  # => [[0, 1], [0, 0]]

  new_c = transposed.map { |value| # => [0, 1]

    value.reduce(:+)               # => 1, => 0

  }

  new_c                            # => [1,0] As expected for first cell.
}

cells                              # => [[1,0],[1,1]] Final result

With another sample data:

cells = [[0,0],[1,1],[2,2]]
delta = [1,1]
plug  = Proc.new {
  cells = cells.map { |cell| [cell, delta].transpose.map { |value| value.reduce(:+) } }
}

plug.call # => [[1, 1], [2, 2], [3, 3]]
plug.call # => [[2, 2], [3, 3], [4, 4]]
plug.call # => [[3, 3], [4, 4], [5, 5]]
plug.call # => [[4, 4], [5, 5], [6, 6]]
plug.call # => [[5, 5], [6, 6], [7, 7]]

Another one:

cells = [[0,0,0],[0,1,2],[1,2,3],[2,3,4]]
delta = [3,2,1]

plug.call # => [[3, 2, 1],   [3, 3, 3],   [4, 4, 4],   [5, 5, 5]]
plug.call # => [[6, 4, 2],   [6, 5, 4],   [7, 6, 5],   [8, 7, 6]]
plug.call # => [[9, 6, 3],   [9, 7, 5],   [10, 8, 6],  [11, 9, 7]]
plug.call # => [[12, 8, 4],  [12, 9, 6],  [13, 10, 7], [14, 11, 8]]
plug.call # => [[15, 10, 5], [15, 11, 7], [16, 12, 8], [17, 13, 9]]

Hope this answers your question better.

Upvotes: 1

Ken Bloom
Ken Bloom

Reputation: 58770

cells.map {|cell| cell.zip(delta).map{|x, y| x + y }}

I don't consider this cleaner than the other solutions that have been proposed.

Upvotes: 1

Ken Bloom
Ken Bloom

Reputation: 58770

cells.map! {|x, y| [x + delta[0], y + delta[1]] }

Note that Linuxios's answer, my answer, and your solution all have different effects if somebody else has a reference to the cells array or to one of the cells contained in the array. Only your answer modifies the original cells in place, so with my solution or Linuxios's solution references might still point to old data.

Upvotes: 1

Linuxios
Linuxios

Reputation: 35783

Here:

cells = cells.map {|c| [c[0] + delta[0], c[1] + delta[1]] }

Upvotes: 2

Related Questions