在纯粹的红宝石脚本中我有这个:
result = JSON.parse result.body_str
count = result && result["ke1"] && result["ke1"]["key2"] && result["ke1"]["key2"]["key3"] && result["ke1"]["key2"]["key3"]["key4"] ?
result["key1"]["key2"]["key3"]["key4"].to_i :
123
有没有办法简化这个?
答案 0 :(得分:6)
count = result["key1"]["key2"]["key3"]["key4"].to_i rescue 123
如果你想制作一个更好的可读性的私人方法,你可以做
def count(result)
result["key1"]["key2"]["key3"]["key4"].to_i
rescue NoMethodError
123
end
我添加了NoMethodError来限制救援可以吞下的错误。尽管争论不休 使用流控制的例外,我更喜欢这个以便于阅读。在一个小功能或一个衬管中,它在技术上甚至不会改变流量,因为它们都保留在一个位置。
如果在具有数百万条记录的紧密循环中使用它,您可能希望使用分析器与其他解决方案进行比较,但您必须根据实际使用情况进行调用。如果在一些可能每天运行5次的代码上使用它,请坚持使用更容易阅读和维护的代码。
答案 1 :(得分:2)
我会这样写,然后把它放在一个模块中,根据需要加入。
<强>代码强>
def value_at_deep_key(hash, path)
path.each_with_index.reduce(hash) do |current, (segment, i) |
case c = current[segment]
when Hash then c
else (i==path.size-1) ? (current.key?(segment) ? c : :NO_MATCH) : {}
end
end
end
<强>实施例强>
value_at_deep_key({a: {b: {c: "cat"}}}, [:a, :b, :c]) #=> "cat"
value_at_deep_key({a: {b: {c: false}}}, [:a, :b, :c]) #=> false
value_at_deep_key({a: {b: {c: nil}}}, [:a, :b, :c]) #=> nil
value_at_deep_key({z: {b: {c: "cat"}}}, [:a, :b, :c]) #=> :NO_MATCH
value_at_deep_key({a: {z: {c: "cat"}}}, [:a, :b, :c]) #=> :NO_MATCH
value_at_deep_key({a: {b: {z: "cat"}}}, [:a, :b, :c]) #=> :NO_MATCH
value_at_deep_key({a: {b: {c: "cat"}}}, [:a, :b]) #=> {:c=>"cat"}
value_at_deep_key({a: {b: {c: "cat"}}}, [:a]) #=> {:b=>{:c=>"cat"}}
value_at_deep_key({z: {b: {c: "cat"}}}, []) #=> {:z=>{:b=>{:c=>"cat"}}}
value_at_deep_key({z: {b: {c: "cat"}}}, [:a, :b, :c]) #=> :NO_MATCH
value_at_deep_key({a: {z: {c: "cat"}}}, [:a, :b, :c]) #=> :NO_MATCH
value_at_deep_key({a: {b: {z: "cat"}}}, [:a, :b, :c]) #=> :NO_MATCH
value_at_deep_key({a: {z: {c: "cat"}}}, [:a, :b, :c, :d]) #=> :NO_MATCH
然后可以写:
val = value_at_deep_key(hash, path)
(val = 123) if (val == :NO_MATCH)
如果最后一个键的值不能是nil
,
else (i==path.size-1) ? (current.key?(segment) ? c : :NO_MATCH) : {}
可以替换为:
else (i==path.size-1) ? c : {}
在这种情况下,如果没有匹配,将返回nil
。
答案 2 :(得分:0)
我偶尔会定义一个这样的方法
def value_at_deep_key hash, path, default=nil
path.inject(hash) {|current,segment| current && current[segment]} || default
end
这使用inject依次获取哈希的每个级别。 你会像这样使用
value_at_deep_key(result, %w(key1 key2 key3 key4), 123)
就我个人而言,我不喜欢使用救援这种东西 - 它可以掩盖错误。
答案 3 :(得分:0)
以下是代码:
def value_at_deep_key(hash, path, default=nil)
path.inject(hash) {|current,segment| current && current[segment]} || default
end
以下是一些结果:
h = {
'key1' => {'key2' => {'key3' => {'key4' => 3}}}
}
p value_at_deep_key(h, %w[key1 key2 key3 key4], 123)
--output:--
3
h = {
'key1' => 1,
'key2' => 2,
'key3' => 3,
'key4' => 4,
}
p value_at_deep_key(h, %w[key1 key2 key3 key4], 123)
--output:--
1.rb:16:in `[]': no implicit conversion of String into Integer (TypeError)
from 1.rb:16:in `block in value_at_deep_key'
from 1.rb:16:in `each'
from 1.rb:16:in `inject'
from 1.rb:16:in `value_at_deep_key'
from 1.rb:19:in `<main>'
h = {
'key1' => {'key2' => {'key3' => 4}}
}
p value_at_deep_key(h, %w[key1 key2 key3 key4], 123)
--output:--
1.rb:16:in `[]': no implicit conversion of String into Integer (TypeError)
def value_at_deep_key(hash, key_sequence, default=nil)
return "No keys to lookup!" if key_sequence.empty?
value = hash
key_sequence.each do |key|
case value
when Hash
value = value[key]
else
value = nil
break
end
end
value.nil? ? default : Integer(value) #A found value of nil produces the default, which is
#also the case when one of the keys doesn't exist in the Hash.
#Because to_i() will silently convert a found string with no leading numbers to 0,
#use Integer() instead, which will throw a descriptive error when trying to convert any String(or Hash or Array) to an int.
end
--output:--
p value_at_deep_key({a: {b: {c: "cat"}}}, [:a, :b, :c], 123) #=> `Integer': invalid value for Integer(): "cat" (ArgumentError)
p value_at_deep_key({a: {b: {c: false}}}, [:a, :b, :c], 123) #=> `Integer': can't convert false into Integer (TypeError)
p value_at_deep_key({a: {b: {c: nil}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({z: {b: {c: "cat"}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {z: {c: "cat"}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {b: {z: "cat"}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {b: {c: "cat"}}}, [:a, :b], 123) #=> `Integer': can't convert Hash into Integer (TypeError
p value_at_deep_key({a: {b: {c: "cat"}}}, [:a], 123) #=> `Integer': can't convert Hash into Integer (TypeError)
p value_at_deep_key({z: {b: {c: "cat"}}}, [], 123) #=> "No keys to lookup!"
p value_at_deep_key({z: {b: {c: "cat"}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {z: {c: "cat"}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {b: {z: "cat"}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {z: {c: "cat"}}}, [:a, :b, :c, :d], 123) #=> 123
p value_at_deep_key(
{'key1' => {'key2' => {'key3' => {'key4' => "4"}}}},
%w[key1 key2 key3 key4],
default=123,
) #=> 4
p value_at_deep_key(
{ 'key1' => {'key2' => {'key3' => "4"}}},
%w[key1 key2 key3 key4],
default=123,
) #=> 123
p value_at_deep_key(
{
'key1' => "1",
'key2' => "2",
'key3' => "3",
'key4' => "4",
},
%w[key1 key2 key3 key4],
default=123,
) #=> 123
p value_at_deep_key(
{ 'key1' => {'key2' => {'key3' => {'key4' => nil}}}},
%w[key1 key2 key3 key4],
default=123,
) #=> 123
p value_at_deep_key(
{'key1' => {'key2' => {'key3' => {'key4' => 'hello'}}}},
%w[key1 key2 key3 key4],
default=123,
) #=> `Integer': invalid value for Integer(): "hello" (ArgumentError)
如果你必须:
...换句话说没有错误,你可以这样做:
def value_at_deep_key(hash, key_sequence, default=nil)
value = hash
key_sequence.each do |key|
case value
when Hash
value = value[key]
else
value = hash.object_id #Some unique value to signal that the Hash lookup failed.
break
end
end
begin
value == hash.object_id ? default : Integer(value)
rescue TypeError, ArgumentError #If the Hash lookup succeeded, but the value is: nil, true/false, a String that is not all numbers, Array, Hash, an object that neither responds to to_int() nor to_i()
default
end
end
p value_at_deep_key({a: {b: {c: "cat"}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {b: {c: false}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {b: {c: nil}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({z: {b: {c: "cat"}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {z: {c: "cat"}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {b: {z: "cat"}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {b: {c: "cat"}}}, [:a, :b], 123) #=> 123
p value_at_deep_key({a: {b: {c: "cat"}}}, [:a], 123) #=> 123
p value_at_deep_key({z: {b: {c: "cat"}}}, [], 123) #=> 123
p value_at_deep_key({z: {b: {c: "cat"}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {z: {c: "cat"}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {b: {z: "cat"}}}, [:a, :b, :c], 123) #=> 123
p value_at_deep_key({a: {z: {c: "cat"}}}, [:a, :b, :c, :d], 123) #=> 123
p value_at_deep_key(
{'key1' => {'key2' => {'key3' => {'key4' => "4"}}}},
%w[key1 key2 key3 key4],
default=123,
) #=> 4
p value_at_deep_key(
{ 'key1' => {'key2' => {'key3' => "4"}}},
%w[key1 key2 key3 key4],
default=123,
) #=> 123
p value_at_deep_key(
{
'key1' => "1",
'key2' => "2",
'key3' => "3",
'key4' => "4",
},
%w[key1 key2 key3 key4],
default=123,
) #=> 123
p value_at_deep_key(
{ 'key1' => {'key2' => {'key3' => {'key4' => nil}}}},
%w[key1 key2 key3 key4],
default=123,
) #=> 123
p value_at_deep_key(
{'key1' => {'key2' => {'key3' => {'key4' => [1, 2, 3] }}}},
%w[key1 key2 key3 key4],
default=123,
) #=> 123