【问题标题】:pushing elements onto an array in a ruby Hash将元素推入 ruby​​ 哈希中的数组
【发布时间】:2011-02-15 20:46:22
【问题描述】:

在 Ruby 中,要创建数组散列并将元素推送到这些数组中,我见过两个习惯用法。我想知道人们更喜欢哪一个,为什么。 (披露:我有自己的看法,但我想确保我没有遗漏一些明显的东西。)

方法 1:使用 Hash 的精美初始化器:

ht = Hash.new {|h,k| h[k]=[]}
ht["cats"] << "Jellicle"
ht["cats"] << "Mr. Mistoffelees"

当您使用尚不存在的键访问 ht 时,此方法会创建一个空数组。

方法 2:简单的初始化器,花哨的访问器:

ht = {}
(ht["cats"] ||= []) << "Jellicle"
(ht["cats"] ||= []) << "Mr. Mistoffelees"

人们是否对哪一种更好(或一种优于另一种的情况)有意见?

【问题讨论】:

    标签: ruby arrays hash


    【解决方案1】:

    有时哈希最初是用数据填充的,后来它只用于检索数据。在这些情况下,我更喜欢第一种可能性,因为默认 proc 可以“清空”(在 Ruby 1.9 中)。

    ht = Hash.new {|h,k| h[k]=[]}
    ht["cats"] << "Jellicle"
    ht["cats"] << "Mr. Mistoffelees"
    ht["dogs"]
    p ht
    #=> {"cats"=>["Jellicle", "Mr. Mistoffelees"], "dogs"=>[]}
    
    ht.default_proc = proc{}
    ht["parrots"] #nil
    p ht
    #=> {"cats"=>["Jellicle", "Mr. Mistoffelees"], "dogs"=>[]} No parrots!
    

    【讨论】:

    • 我喜欢通过重新定义 default_proc 来“关闭”初始化程序的细节——这很有用。这解决了我的部分担忧(见下文)。
    【解决方案2】:

    在 OP 中,我说我有自己的看法。在这里。

    虽然“花哨的初始化程序”方法很优雅,但它可能会导致一些非常出乎意料的行为——特别是在你不期望的时候生成密钥——而且通过查看哈希表无法知道这一点。

    考虑以下几点:

    >> ht1 = Hash.new {|h,k| h[k]=[]}
    >> ht2 = {}
    >> ht1["cats"] << "Jellicle"
    => ["Jellicle"]
    >> (ht2["cats"] ||= []) << "Jellicle"
    => ["Jellicle"]
    

    到目前为止一切顺利——ht1 和 ht2 是相同的。但是:

    >> ht1["dogs"] ? "got dogs" : "no dogs"
    => "got dogs"
    >> ht2["dogs"] ? "got dogs" : "no dogs"
    => "no dogs"
    

    请注意,只需访问 ht1[some_key] 即可更改哈希表的状态,即它会创建一个新条目。您可能会争辩说,最终用户应该始终使用 has_key?() 来测试是否存在哈希条目——而且你是对的——但上述用法是公认的习惯用法。哈希表自动创建条目将是一个意想不到的副作用,因此如果哈希表曾经暴露给最终用户,您应该小心。 (但是请注意,steenslag 的回答显示了如何将其关闭。)

    【讨论】:

    • 无论您选择哪个选项,您都必须以某种方式在整个代码中跟踪行为/语义。总的来说,第一个选项对我来说似乎更干净,但这最终可能归结为个人喜好。
    【解决方案3】:

    如果您事先知道每个键的编号和名称,那么您可以使用第一个选项。或者更简单的

    ht = { "cats" => [] }
    

    否则,如果您不想(不需要)预初始化哈希,则第二个选项是一个不错的选择。

    【讨论】:

    • 即使您事先不知道哈希键的名称,第一个仍然有效。魔法发生在 ht 的定义中一次,从那时起“正常工作”。
    【解决方案4】:

    我个人更喜欢:

    ht = Hash.new {|h,k| h[k]=[]}
    ht["cats"] << "Jellicle"
    ht["cats"] << "Mr. Mistoffelees"
    

    对我来说,这是维护和自我记录的问题。哈希初始化脏工作发生一次。从那时起,所有对哈希中数组的分配都以标准方式发生,这将导致您的代码看起来正常。

    替代方法:

    ht = {}
    (ht["cats"] ||= []) << "Jellicle"
    (ht["cats"] ||= []) << "Mr. Mistoffelees"
    

    一开始看起来很正常,但每个作业都有我所说的“视觉噪音”。我们必须在精神上解码||= [] 的含义,每次将某些内容推送到散列中的数组时。这会让人精神疲惫,如果你在整个代码中都这样做,会导致代码看起来不那么优雅,并且会不断地重新评估代码在 THAT 处所做的到底是什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 2010-12-11
      相关资源
      最近更新 更多