嵌入对象的路径

saw*_*awa 5 ruby arrays hash

给定一个嵌套数组或散列作为接收器,并将某个对象作为参数,如果接收器包含该对象,则返回路径到对象出现的最佳方法是什么nil?我将路径定义为数组索引或散列键的数组,导致该对象.参数对象永远不会是任何哈希键,并且永远不会出现多次.例如,我希望:

[
  :a,
  [:b, :c, {:d => :foo}],
  :e,
]
.path_to(:foo) # => [1, 2, :d]

{
  :a => [3, "foo"],
  :b => 5,
  :c => 2,
}
.path_to(3) # => [:a, 0]
Run Code Online (Sandbox Code Playgroud)

如果没有发生,请返回nil:

[:foo, "hello", 3]
.path_to(:bar) => nil
Run Code Online (Sandbox Code Playgroud)

如果没有人提出合理的答案,那么我很快就会发布自己的答案.

Rea*_*onk 2

没有什么比一点递归更好的了。

require 'minitest/autorun'

class Array
  def path_to(obj)
    # optimize this
    Hash[self.each.with_index.to_a.map {|k,v| [v,k]}].path_to(obj)
  end
end

class Hash
  def path_to(obj)
    inverted = self.invert
    if inverted[obj]
      [inverted[obj]]
    else
      self.map {|k, v|
        if v.respond_to?(:path_to)
          if res = v.path_to(obj)
            [k] + res
          end
        end
      }.find {|path|
        path and path[-1] != nil
      }
    end
  end
end

describe "path_to" do
  it "should work with really simple arrays" do
    [:a, :e,].path_to(:a).must_equal [0]
  end
  it "should work with simple arrays" do
    [:a, [:b, :c], :e,].path_to(:c).must_equal [1, 1]
  end
  it "should work with arrays" do
    [:a, [:b, :c, {:d => :foo}], :e,].path_to(:foo).must_equal [1, 2, :d]
  end
  it "should work with simple hashes" do
    {:d => :foo}.path_to(:foo).must_equal [:d]
  end
  it "should work with hashes" do
    ({:a => [3, "foo"], :b => 5, :c => 2,}.path_to(3).must_equal [:a, 0])
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 他的解决方案在模块封装方面也更好,IIRC ruby​​ 人们不喜欢搞乱核心对象,这是一种耻辱。 (2认同)