Reputation: 43113
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
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
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
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
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
Reputation: 35783
Here:
cells = cells.map {|c| [c[0] + delta[0], c[1] + delta[1]] }
Upvotes: 2