Home > front end >  Ruby dynamically updating value in nested array
Ruby dynamically updating value in nested array

Time:12-21

In Ruby, with a 1D Array, I can dynamically select elements by passing an Integer key in brackets, as follows:

example =  [0,1,2,[3,4]]
i = 2

example[i]
==> 2

What I would like to achieve, is to dynamically update an element in a multi-dimensional Array by passing an Array of Integers, each representing the index to select in each array. Example of what I'd like to achieve:

example =  [0,1,2,[3,4]]
path = [3, 1] (corresponds to the 4)

example[*path or some other syntax] = 9
example 
==> [0,1,2,[3,9]]

What I've tried is storing the result with each path iteration:

temp = example
path.each {|index|
  temp = temp[index]
}
temp
==> 4

This successfully identifies the element I'd like to update. However, it appears to have stored a copy, rather than to reference the original location, as:

temp = 9
example
==> [0,1,2,[3,4]]

How can I update the base array example without hardcoding path in individual brackets?

Clarification after a comment: I don't know the path length in advance, which is why hardcoding isn't viable.

CodePudding user response:

Define a function, something along the lines of:

def deep_set! val, arr, *path
  path[0...-1].each {|i| arr = arr[i]}
  arr[path[-1]] = val
end
arr =  [0,1,2,[3,4]]
deep_set! 9, arr, 3 ,1

arr #=> [0, 1, 2, [3, 9]]

CodePudding user response:

Your iteration is almost there, you just need to stop one step before you run through path so that you can have the array you need to modify rather than the element.

So split the path into the pieces you want:

*p, target = path
# [3], 1

Then use #inject to find the array:

ary = p.inject(example) { |i, a| a[i] }
# [3, 4]

and then do your assignment:

ary[target] = 9

Of course you'll need to add some logic to deal with the unexpected such as path leading you to a non-array element or path not matching the structure of example (consider path = [11, 6, 23] in your example).

  • Related