require 'pp'
class Hash
def deep_merge!(second)
merger = proc { |key,v1,v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
self.merge!(second, &merger)
end
def nested_hash(array)
node = self
array.each do |i|
node[i]=Hash.new if node[i].nil?
node = node[i]
end
self
end
def merge_nested_hash!(nested_hash)
deep_merge!(nested_hash)
end
def each_trie_path
raise ArgumentError unless block_given?
self.class.each_trie_path(self) { |path, object| yield(path, object) }
end
protected
def self.each_trie_path(object, path = [], &block)
if object.is_a?(Hash)
object.each do |key, value|
if key == true && value == {}
if path == [:root]
yield(path, {true=>{}})
next
end
yield(path, object)
end
self.each_trie_path(value, [path , key].flatten, &block)
end
else
yield(path, object)
end
end
end
class Trie
@hash = Hash.new.merge_nested_hash!(Hash.new)
class << self; attr_accessor :hash; end
def initialize
Trie.hash.merge_nested_hash!({:root=>{}})
end
def add_int(int)
ia = int.to_s.scan(/[[:digit:]]/).map { |i| i.to_i }
ia.unshift(:root).push(true)
Trie.hash.merge_nested_hash!(Hash.new.nested_hash(ia))
end
def matchi(int)
ia = int.to_s.scan(/[[:digit:]]/).map { |i| i.to_i }
node = Trie.hash.fetch(:root,nil)
ia.each do |digit|
node = node[digit]
return false unless node
end
node.fetch(true,nil) ? true : false
end
def mfpi(int)
ia = int.to_s.scan(/[[:digit:]]/).map { |i| i.to_i }
node = Trie.hash.fetch(:root,nil)
ia.each do |digit|
node = node[digit]
return false unless node
end
return true
end
def add_word(word)
ca = word.split(//u)
ca.unshift(:root).push(true)
Trie.hash.merge_nested_hash!(Hash.new.nested_hash(ca))
end
def match(word)
ca = word.split(//u)
node = Trie.hash.fetch(:root,nil)
ca.each do |char|
node = node[char]
return false unless node
end
node.fetch(true,nil) ? true : false
end
def mfpw(word)
ca = word.split(//u)
node = Trie.hash.fetch(:root,nil)
ca.each do |char|
node = node[char]
return false unless node
end
return true
end
end
trie = Trie.new
p Trie.hash
trie.add_word("word")
pp Trie.hash
p trie.match("word")
p trie.match("word2")
trie.add_word("word2")
p trie.match("word2")
pp Trie.hash
trie.add_word("")
p trie.match("")
pp Trie.hash
puts
p trie.match("word")
p trie.mfpw("wor")
puts
trie.add_int(12345)
p Trie.hash
trie.add_int(12980345)
pp Trie.hash
trie.add_int(8512)
pp Trie.hash
p trie.matchi(8512)
p trie.matchi(85)
p trie.mfpi(85)
p trie.matchi(51)
puts
puts
pp Trie.hash
paths = []
Trie.hash.each_trie_path { |path, value| paths.push([ path ]) }
puts
paths.each { |x| p x }
puts
require 'pp'
class Hash
def Hash.new_nested_hash
Hash.new{|h,k| h[k]=Hash.new(&h.default_proc) }
end
end
class Trie
@hash = Hash.new_nested_hash
class << self; attr_accessor :hash; end
def <<(word)
ca = word.split(//u)
wl = ca.size
str = ""
wl.times { |x| str << "[ca.at(#{x})]" }
str = "Trie.hash" << str << "[true]"
eval(str)
end
def match(word)
ca = word.split(//u)
wl = ca.size
str = ""
wl.times { |x| str << ".fetch(ca.at(#{x}),nil)" }
str = "Trie.hash" << str << ".fetch(true,nil)"
ret = eval(str) rescue nil
ret == {} ? true : false
end
end
trie = Trie.new
trie << "word"
pp Trie.hash
p trie.match("word")
p trie.match("word2")
trie << "word2"
p trie.match("word2")
pp Trie.hash
trie << ""
p trie.match("")
pp Trie.hash
require 'pp'
class Hash
def Hash.new_nested_hash
Hash.new{|h,k| h[k]=Hash.new(&h.default_proc) }
end
end
class Hash
def each_trie_path
raise ArgumentError unless block_given?
self.class.each_trie_path(self) { |path, object| yield(path, object) }
end
protected
def self.each_trie_path(object, path = [], &block)
if object.is_a?(Hash)
object.each do |key, value|
if key == true && value == {}
if path == [:root]
yield(path, {true=>{}})
next
end
yield(path, object)
end
self.each_trie_path(value, [path , key].flatten, &block)
end
else
yield(path, object)
end
end
end
class Trie
@hash = Hash.new_nested_hash
class << self; attr_accessor :hash; end
def initialize
Trie.hash[:root]
end
def add_int(int)
ia = int.to_s.scan(/[[:digit:]]/).map { |i| i.to_i }
ia.unshift(:root)
str = ""
ia.size.times { |x| str << "[ia.at(#{x})]" }
str = "Trie.hash" << str << "[true]"
eval(str)
end
def matchi(int)
ia = int.to_s.scan(/[[:digit:]]/).map { |i| i.to_i }
node = Trie.hash.fetch(:root,nil)
ia.each do |digit|
node = node.fetch(digit,nil)
return false unless node
end
node.fetch(true,nil) ? true : false
end
def mfpi(int)
ia = int.to_s.scan(/[[:digit:]]/).map { |i| i.to_i }
node = Trie.hash.fetch(:root,nil)
ia.each do |digit|
node = node.fetch(digit,nil)
return false unless node
end
return true
end
def <<(word)
ca = word.split(//u)
ca.unshift(:root)
str = ""
ca.size.times { |x| str << "[ca.at(#{x})]" }
str = "Trie.hash" << str << "[true]"
eval(str)
end
def match(word)
ca = word.split(//u)
ca.unshift(:root)
str = ""
ca.size.times { |x| str << ".fetch(ca.at(#{x}),nil)" }
str = "Trie.hash" << str << ".fetch(true,nil)"
ret = eval(str) rescue nil
ret == {} ? true : false
end
def match2(word)
ca = word.split(//u)
node = Trie.hash.fetch(:root,nil)
ca.each do |char|
node = node.fetch(char,nil)
return false unless node
end
node.fetch(true,nil) ? true : false
end
def mfpw(word)
ca = word.split(//u)
node = Trie.hash.fetch(:root,nil)
ca.each do |char|
node = node.fetch(char,nil)
return false unless node
end
return true
end
end
trie = Trie.new
trie << "word"
pp Trie.hash
p trie.match("word")
p trie.match("word2")
trie << "word2"
p trie.match("word2")
pp Trie.hash
trie << ""
p trie.match("")
pp Trie.hash
puts
p trie.match2("word")
p trie.mfpw("wor")
puts
trie.add_int(8512)
pp Trie.hash
p trie.matchi(8512)
p trie.matchi(85)
p trie.mfpi(85)
p trie.matchi(51)
puts
puts
pp Trie.hash
paths = []
Trie.hash.each_trie_path { |path, value| paths.push([ path ]) }
puts
paths.each { |x| p x }
puts