Ruby:创建数组项";“随需应变”;

Ruby:创建数组项";“随需应变”;,ruby,arrays,Ruby,Arrays,在Ruby with Hash中,我可以做到: h = Hash.new { |h,k| h[k] = "created #{k}" } 因此,每当我尝试使用散列中不存在的密钥访问一个项时,它都会调用该块并创建这个新项并使用该密钥存储 是否有类似的方法来处理阵列?默认情况下,不,我认为这是不可能的。如果你愿意做一些猴子补丁,你可以自己添加一个类似的方法。例如,通过使用接受块的get方法扩展Array,可以模拟所需的内容 当没有给出任何块时,get方法将像常规的[]一样工作。当您传递一个块且值为

在Ruby with Hash中,我可以做到:

h = Hash.new { |h,k| h[k] = "created #{k}" }
因此,每当我尝试使用散列中不存在的密钥访问一个项时,它都会调用该块并创建这个新项并使用该密钥存储


是否有类似的方法来处理阵列?

默认情况下,不,我认为这是不可能的。如果你愿意做一些猴子补丁,你可以自己添加一个类似的方法。例如,通过使用接受块的
get
方法扩展
Array
,可以模拟所需的内容

当没有给出任何块时,
get
方法将像常规的
[]
一样工作。当您传递一个块且值为
nil
时,它将在索引
i
处存储来自该块的任何结果

class Array
  def get(i, &block)
    return self[i] if !block || !self[i].nil?

    self[i] = block.call(i)
  end
end

array = [1, 2]
array.get(0) # => 1 

array.get(5) # => nil
array.get(5) { |i| "Created index #{i}" } # => "Created index 5"

p array # => [1, 2, nil, nil, nil, "Created index 5"] 

数组。新的
方法可以接收块。它传递元素的索引,块的结果存储在数组中

Array.new(3) { |index| index ** 2 }
# => [0, 1, 4]
但是,所有元素都将在调用该方法时创建。它们也将被存储在块中,没有办法阻止

我们可以将
数组
子类化,并实现所需的
散列
类行为

class CustomArray < Array
  def [](index)
    if super.nil? then @default_proc.call self, index end
    super
  end
end

class << CustomArray
  def new(*arguments, **keyword_arguments, &block)
    if arguments.empty? and block
      super().tap do |array|
        array.instance_variable_set :@default_proc, block
      end
    else super end
  end
end
看着它跑

请注意,由于
nil
的含义,此实现存在问题。在这种情况下,由于数组的工作方式,它被定义为空值,这在连续内存的上下文中是合理的。如果您将一个元素存储在大于数组大小的索引处,它将用
nil
填充空格,以指示最后一个元素和刚刚插入的元素之间的空白


如果<代码> nIL/COD>是一个有意义的值,考虑使用<代码> hash 使用整数键,而不是<代码>数组 .< /P>可能的马克斯的副本,这不是同一个问题,尽管它有很多共同之处,但那里的答案不能为我的问题提供解决方案。(大小){|索引|块}将创建一个大小为

size
的数组,当我尝试访问以前不存在的密钥时,它将不会再次调用该块。我建议将该方法命名为
fetch
。这将使其与
哈希
API一致。此外,我认为读卡器方法不应隐式修改该数组。@MatheusMoreira
fetch
已存在于数组中,它类似于
[]
,但在索引超出范围时引发异常。我不想更改现有方法的语义。我只是向您展示可以添加替代方法。
array = CustomArray.new { |array, index| array[index] = index + 2 }

p array[10]
# => 12

p array
# => [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 12]