簡體   English   中英

如何從提供的參數遞歸定義Ruby中的Hash?

[英]How do I recursively define a Hash in Ruby from supplied arguments?

這段代碼填充了@options哈希。 values是一個包含零個或多個異構項的Array 如果使用作為Hash條目的參數調用populate ,它將使用您為每個條目指定的值來采用默認值。

def populate(*args)
  args.each do |a|
    values = nil
    if (a.kind_of? Hash)
      # Converts {:k => "v"} to `a = :k, values = "v"`
      a, values = a.to_a.first
    end

    @options[:"#{a}"] ||= values ||= {}
  end
end

我想做的是改變populate ,以便遞歸填充@options 有一種特殊情況:如果要填充鍵的值是一個完全由(1)符號組成的數組或(2)鍵是符號(或兩者的某種組合)的哈希值,那么它們應該被視為子鍵而不是與該鍵關聯的值,並且應該遞歸地重新應用用於評估原始populate參數的相同邏輯。

這有點難以言喻,所以我寫了一些測試用例。 以下是一些測試用例和@options的預期值:

populate :a
=> @options is {:a => {}}

populate :a => 42
=> @options is {:a => 42}

populate :a, :b, :c
=> @options is {:a => {}, :b => {}, :c => {}}

populate :a, :b => "apples", :c
=> @options is {:a => {}, :b => "apples", :c => {}}

populate :a => :b
=> @options is {:a => :b}

# Because [:b] is an Array consisting entirely of Symbols or
# Hashes whose keys are Symbols, we assume that :b is a subkey
# of @options[:a], rather than the value for @options[:a].
populate :a => [:b]
=> @options is {:a => {:b => {}}}

populate :a => [:b, :c => :d]
=> @options is {:a => {:b => {}, :c => :d}}

populate :a => [:a, :b, :c]
=> @options is {:a => {:a => {}, :b => {}, :c => {}}}

populate :a => [:a, :b, "c"]
=> @options is {:a => [:a, :b, "c"]}

populate :a => [:one], :b => [:two, :three => "four"]
=> @options is {:a => :one, :b => {:two => {}, :three => "four"}}

populate :a => [:one], :b => [:two => {:four => :five}, :three => "four"]
=> @options is {:a => :one,
                :b => {
                   :two => {
                      :four => :five
                      }
                   },
                   :three => "four"
                }
               }

如果populate的簽名需要改變以適應某種遞歸版本是可以接受的。 理論上可以發生的嵌套量沒有限制。

關於我如何解決這個問題的任何想法?

所以這里有一些簡單的代碼可行。

def to_value args
  ret = {}
  # make sure we were given an array
  raise unless args.class == Array
  args.each do |arg|
    case arg
    when Symbol
      ret[arg] = {} 
    when Hash
      arg.each do |k,v|
        # make sure that all the hash keys are symbols
        raise unless k.class == Symbol
        ret[k] = to_value v 
      end           
    else    
      # make sure all the array elements are symbols or symbol-keyed hashes
      raise         
    end     
  end
  ret
rescue
  args
end
def populate *args
  @options ||= {}
  value = to_value(args)
  if value.class == Hash
    @options.merge! value
  end
end

它確實偏離了您的測試用例:

  • 測試用例populate :a, :b => "apples", :c是ruby語法錯誤。 Ruby會假設方法的最后一個參數是一個哈希(當沒有給出大括號時),但不是非最終的,正如你在這里假設的那樣。 給定的代碼是語法錯誤(無論populate的定義),因為它假定:c是一個散列鍵,並在查找時找到行尾:c的值。 populate :a, {:b => "apples"}, :c按預期工作
  • 測試用例populate :a => [:one], :b => [:two, :three => "four"]返回{:a=>{:one=>{}}, :b=>{:two=>{}, :three=>"four"}} 這與populate :a => [:b]測試用例一致populate :a => [:b]

Ruby不是Perl, =>僅在真正的Hash定義內部工作或在方法調用中作為最終參數。 您想要的大多數事情都會導致語法錯誤。

您確定僅限於Ruby語法支持的populate值是否值得?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM