Ruby 动态更新嵌套数组中的值

Posted

技术标签:

【中文标题】Ruby 动态更新嵌套数组中的值【英文标题】:Ruby dynamically updating value in nested array 【发布时间】:2022-01-22 12:00:03 【问题描述】:

在 Ruby 中,使用 1D Array,我可以通过在括号中传递 Integer 键来动态选择元素,如下所示:

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

example[i]
==> 2

我想要实现的是通过传递ArrayIntegers 来动态更新多维Array 中的元素,每个元素代表要在每个数组中选择的索引。我想要实现的示例:

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]]

我尝试的是存储每次路径迭代的结果:

temp = example
path.each |index|
  temp = temp[index]

temp
==> 4

这成功识别了我要更新的元素。但是,它似乎存储了一个副本,而不是引用原始位置,如:

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

如何更新基本数组 example 而无需在单独的括号中硬编码 path

评论后澄清:我事先不知道path 的长度,这就是硬编码不可行的原因。

【问题讨论】:

example[3][1] = 9 还不够吗? 不,因为我希望能够容纳多个 path 长度。带括号的硬编码将我限制为两步 path 写一个方法。传入数组对象,然后是索引。您必须使您的方法能够接受任意数量的索引。 【参考方案1】:

您的迭代即将完成,您只需在运行path 之前停止一步,这样您就可以获得需要修改的数组而不是元素。

所以将path 拆分成你想要的部分:

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

然后使用#inject查找数组:

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

然后做你的任务:

ary[target] = 9

当然,您需要添加一些逻辑来处理意外情况,例如 path 导致您进入非数组元素或 pathexample 的结构不匹配(请考虑您的 path = [11, 6, 23]示例)。

您也可以使用#dig 代替#inject

ary = example.dig(*p)
ary[target] = 9

# or
example.dig(*p)[target] = 9

这将解决一些有问题的paths,如果ary.nil?,您将不得不决定该怎么做。

【讨论】:

【参考方案2】:

定义一个函数,类似于:

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]]

【讨论】:

【参考方案3】:

我假设path 至少包含一个元素。

你可以使用Array#dig。

def dig_and_replace(arr, path, replacement)
  *first, last = path
  if first.empty?
    arr[last] = replacement
  else
    arr.dig(*first)[last] = replacement
  end
  arr
end
arr = [0,1,2,[3,4]]
dig_and_replace(arr,[3,1],99)
  #=> [0,1,2,[3,99]]
arr
  #=> [0,1,2,[3,99]]
dig_and_replace([0,1,2,[3,             4              ]],[3,1],
  cat:'meow', dog:'woof')
  #=>           [0,1,2,[3,:cat=>"meow", :dog=>"woof"]]
dig_and_replace([0,[1,[2,3,[4,5,[6, 7],8],9],10,11]],[1,1,2,2,1],99)
  #=>           [0,[1,[2,3,[4,5,[6,99],8],9],10,11]]
dig_and_replace([0,[1,[2,3,[4,5,[6,7],8],9],10,11]],[1,1,2],99)
  #=>           [0,[1,[2,3,     99,      9],10,11]]

注意如果

path = [1,2,3,4]
*first, last = path

然后

first #=> [1,2,3]
last  #=> 4

【讨论】:

以上是关于Ruby 动态更新嵌套数组中的值的主要内容,如果未能解决你的问题,请参考以下文章

ReactJS:如何使用动态键访问和更新嵌套状态对象?

根据另一列中的值更新 BigQuery 中的嵌套数组

MongoDB - 仅当嵌套数组中的所有条目存在时才更新它们

如何使用动态索引更新对象数组?

使用动态更新查询更新 Ledger_stat 表中的天数列的值

使用嵌套字段中的值更新字段