我有一個嵌套的散列/陣列,例如:如何訪問嵌套散列/數組中的元素,給定類似「a.b.0.x」的路徑?
target = {
:a => {
"b" => [
{
:x => "here"
}
]
}
}
其中散列鍵是從來沒有的數字。給定一串由"."
(例如"a.b.0.x"
)表示的target[:a]["b"][0][:x]
之間的索引/鍵,我如何訪問相應的元素?
我有一個嵌套的散列/陣列,例如:如何訪問嵌套散列/數組中的元素,給定類似「a.b.0.x」的路徑?
target = {
:a => {
"b" => [
{
:x => "here"
}
]
}
}
其中散列鍵是從來沒有的數字。給定一串由"."
(例如"a.b.0.x"
)表示的target[:a]["b"][0][:x]
之間的索引/鍵,我如何訪問相應的元素?
path = "a.b.0.x"
path.split('.').reduce(target) do |acc, val|
case acc
when Array
break nil unless /\A\d+\z/ === val
acc[val.to_i]
when Hash
next acc[val.to_i] if /\A\d+\z/ === val && acc[val.to_i]
acc[val] || acc[val.to_sym]
else break nil
end
end rescue nil
#⇒ "here"
鑑於rails:'target.with_indifferent_access.dig (* path.split( ''))'。如果不需要漠不關心的訪問,那麼active_support也是如此。 –
@SergioTulentsev給定標籤指定Rails糟透了(像往常一樣:) – mudasobwa
啊,也有陣列。在這種情況下,你的答案確實更好。 –
鑑於這種訪問的邊緣情況,我建議創建一個新的類來處理這種情況並將輸入均勻化爲一致的結構。在這種情況下,Hash
(可能更邊緣的情況下評論歡迎)
class DepthAccessor
class AccessFailure < StandardError
def initialize(val,current=nil,full=nil,depth=nil)
super(
if full && depth
"Failed to find #{val.inspect} for #{current.inspect}:#{current.class} in #{full.inspect} at depth #{depth}"
else
val
end
)
end
end
def initialize(target)
raise ArgumentError, "#{target.inspect}:#{target.class} must respond_to :each_with_object" unless target.respond_to?(:each_with_object)
@target = homogenize(target)
end
def path_search(path,sep: '.',raise_on_fail: true)
split_path = path.split(sep)
split_path.each_with_index.inject(@target) do |acc,(val,idx)|
begin
acc.is_a?(Hash) ? acc[val] : raise
rescue StandardError
if raise_on_fail
raise AccessFailure.new(val,acc,@target,split_path[0..idx].join(sep))
else
nil
end
end
end
end
private
def homogenize(val)
case val
when Array
val.each_with_index.with_object({}) {|(v,idx),obj| obj[idx.to_s] = homogenize(v) }
when Hash
val.each_with_object({}) { |(k,v),obj| obj[k.to_s] = homogenize(v) }
else
val
end
end
end
當你創建一個新的實例中的所有鍵都轉換爲Strings
和所有Array
轉換爲使用index
爲key
Hash
ES
然後使用這樣
target = {
:a => {
"b" => [
{
:x => "here"
}
]
}
}
DepthAccessor.new(target).path_search('a.b.0.x')
#=> "here"
DepthAccessor.new(target).path_search('a.b.c.x')
#=> Failed to find "c" for {"0"=>{"x"=>"here"}}:Hash in {"a"=>{"b"=>{"0"=>{"x"=>"here"}}}} at depth a.b.c
如果Array
小號的預訂要求那麼這裏是另一個例子(有一些額外的功能)Example
問題尚不清楚。你怎麼知道字符串中的「a」部分是爲了「:a」還是「a」?你怎麼知道'0'是否爲'0','「0」'或':0'? – sawa
我不認爲這是很好的編碼口味。 – Daniel
@Daniel爲什麼呢?它是例如完全有效的快速調整巨大的配置。作爲用戶_,我當然會感謝開發人員通過點符號提供了對設置的訪問權限。 – mudasobwa