如何在ruby中链接取消引用?
我想要一个方法如何在ruby中链接取消引用?,ruby,Ruby,我想要一个方法t.find_first[:a,:b,:c],:d,:e]用于散列t,它返回第一组解引用的键 对于上面的示例,它将相当于t.try(:[],:a).try(:[],:b).try(:[],:c)| | t.try(:[],:d).try(:[],:e) 目前我在: def find_first t, *keysets keysets.each do |keys| val = val || keys.inject(t){ |h, key| h.try(:[], key)
t.find_first[:a,:b,:c],:d,:e]
用于散列t
,它返回第一组解引用的键
对于上面的示例,它将相当于t.try(:[],:a).try(:[],:b).try(:[],:c)| | t.try(:[],:d).try(:[],:e)
目前我在:
def find_first t, *keysets
keysets.each do |keys|
val = val || keys.inject(t){ |h, key| h.try(:[], key) }
end
end
我想不是特别优雅,但有时候少施魔法更好
class FindFirst
def self.find_first(t, *keysets)
keysets.each do |keyset|
return keyset if can_dereference_chain?(t, keyset)
end
nil
end
def self.can_dereference_chain?(t, keyset)
keys = keyset.dup
key = keys.shift
if value = t[key]
keys.empty? ? true : can_dereference_chain?(value, keys)
else
false
end
end
end
RSpec.describe FindFirst do
subject { FindFirst }
let(:t) { {a:{b:{c:1}}} }
let(:keyset_1) { [:a, :b, :c] }
let(:keyset_2) { [:a, :b, :d] }
describe "when first keyset works" do
it "returns the first keyset" do
expect(subject.find_first(t, keyset_1)).to eq keyset_1
expect(subject.find_first(t, keyset_1, keyset_2)).to eq keyset_1
end
end
describe "when no keysets work" do
it "returns nil" do
expect(subject.find_first(t, keyset_2)).to eq nil
expect(subject.find_first(t, [])).to eq nil
expect(subject.find_first({}, keyset_1, keyset_2, [])).to eq nil
end
end
describe "when first keyset does not work" do
describe "and second keyset does" do
it "returns the second keyset" do
expect(subject.find_first(t, keyset_2, keyset_1)).to eq keyset_1
end
end
end
end
没有理由为此创建特殊方法 Ruby<2.3
value = t.try(:[], :a).try(:[], :b).try(:[], :c)
value ||= t.try(:[], :d).try(:[], :e)
Ruby>=2.3:
value = t&.[](:a)&.[](:b)&.[](:c)
value ||= t&.[](:d)&.[](:e)
虽然这个问题是间接提出的,但从方法签名来看,您可能试图进入一个嵌套的散列,就像params对象一样
如果是这样的话,你应该看看这个。如果你不在2.3上,你可以随时把它修补好
value = t.dig(:a, :b, :c)
value ||= t.dig(:d, :e)
不使用散列#dig
进入散列的另一种模式如下:
params.fetch(:a, {}).fetch(:b, {})[:c]
你有没有尝试过把它写得更有程序性?您的长格式版本可能会被折叠成一系列在组中迭代的调用。我使用
inject
尝试了一些东西,但看起来不对。@将发布您尝试过的任何内容。通常情况下,解决方案就在你能得到的范围内,你只需要在正确的方向上轻推一下就可以了<代码>挖掘看起来非常有用。@只需根据需要编写任意数量的| |=
作业即可。此外,Array#dig
也存在。
h = { a: :d, c: :f, d: :e, f: :a }
possible_sequences = [[:a, :b, :c], [:d, :e, :f], [:a, :d, :e]]
possible_sequences.find { |a| a[1..-1].reduce(a[0]) { |t,k| k if (t && h[t]==k) } }
#=> [:a, :d, :e]