Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Path to an embedded object

Tags:

arrays

ruby

hash

Given a nested array or hash as the receiver and some object as the argument, what is the best way to return the path to an occurrence of the object if the receiver includes the object, or nil otherwise? I define path as an array of array indices or hash keys that leads to the object. The argument object will never be any of the hash keys, and will never appear more than once. For example, I expect:

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

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

When there is no occurrence, return nil:

[:foo, "hello", 3]
.path_to(:bar) => nil

If no one comes up with a reasonable answer, then I will post my own answer shortly.

like image 675
sawa Avatar asked Mar 05 '14 18:03

sawa


1 Answers

Here you are my own recursive solution. I am sure that it could be improved but it is a good start and works exactly as requested.

# path.rb
module Patheable
  def path_to item_to_find
    path = []
    find_path(self, item_to_find, path)
    result = path.empty? ? nil : path
    result.tap { |r| puts r.inspect } # just for testing
  end

  private 

  def find_path(current_item, item_to_find, result)
    if current_item.is_a?(Array)
      current_item.each_with_index do |value, index| 
        find_path(value, item_to_find, result.push(index))
      end
    elsif current_item.is_a?(Hash)
      current_item.each do |key, value| 
        find_path(value, item_to_find, result.push(key))
      end
    else
      result.pop unless current_item == item_to_find
    end
  end
end

class Array
  include Patheable
end

class Hash
  include Patheable
end

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

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

[:foo, "hello", 3].path_to(:bar)  # => nil
#end path.rb

# example of use
$ ruby path.rb
[1, 2, :d]
[:a, 0]
nil
like image 50
Rafa Paez Avatar answered Oct 19 '22 23:10

Rafa Paez