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

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

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

example[i]
==> 2

我想要实现的是通过传递Array 的Integers 来动态更新多维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。
  • 写一个方法。传入数组对象,然后是索引。您必须使您的方法能够接受任意数量的索引。

标签: arrays ruby


【解决方案1】:

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

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

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

然后使用#inject查找数组:

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

然后做你的任务:

ary[target] = 9

当然,您需要添加一些逻辑来处理意外情况,例如 path 导致您进入非数组元素或 path 与 example 的结构不匹配(请考虑您的 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
      

      【讨论】:

        猜你喜欢
        • 2019-01-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-30
        • 1970-01-01
        • 2018-01-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多