I recently did a class assignment where I made a really hacky data structure. I ended up using nested hashes, which seems like a good idea, but is really hard to iterate through and manage.
I was doing general stuff, like one tag maps to a hash of items that map to prices and stuff like that. But some of them were getting more complicated.
I know that rails uses a lot of more elegant seeming stuff with symbols and such (which I never use shameful face) and I was wondering how I could optimize this. For example if I had my nested hashes something like this
h["cool"][????][1.2]
is there a graceful way of pulling those values out? Maybe I'm just a total newbie in this regard but I wanted to set things stra开发者_JS百科ight before I started doing more things. Maybe I'm even looking for something different like a mix of array/hash or something. Please let me know!
It looks like you need to think about structuring your data more rigorously. Try creating a class for your items, which can contain prices among other things, and perhaps organising them in the way you need to access them. Think about what you want and place the information in structures in a way that makes sense to you. Anything else is a waste of time, both now and three months down the line when you need to extend the system and find you can't.
Yes, it'll be quite a bit of work, and yes, it'll be worth it.
Edit: Revised to provide the rough path to the item. It can't know the name of the variable though.
Try this:
def iterate_nested(array_or_hash, depth = [], &block)
case array_or_hash
when Array:
array_or_hash.each_with_index do |item, key|
if item.class == Array || item.class == Hash
iterate_nested(item, depth + [key], &block)
else
block.call(key, item, depth + [key])
end
end
when Hash:
array_or_hash.each do |key, item|
if item.class == Array || item.class == Hash
iterate_nested(item, depth + [key], &block)
else
block.call(key, item, depth + [key])
end
end
end
end
It should iterate to any depth necessary, limited by memory, etc, and return the key and item and depth of the returned item. Works with both hashes and arrays.
If you test with:
iterate_nested([[[1,2,3], [1,2,3]], [[1,2,3], [1,2,3]], [[1,2,3], [1,2,3]]]) do |key, item, depth|
puts "Element: <#{depth.join('/')}/#{key}> = #{item}"
end
It yields:
Element: <0/0/0/0> = 1
Element: <0/0/1/1> = 2
Element: <0/0/2/2> = 3
Element: <0/1/0/0> = 1
Element: <0/1/1/1> = 2
Element: <0/1/2/2> = 3
Element: <1/0/0/0> = 1
Element: <1/0/1/1> = 2
Element: <1/0/2/2> = 3
Element: <1/1/0/0> = 1
Element: <1/1/1/1> = 2
Element: <1/1/2/2> = 3
Element: <2/0/0/0> = 1
Element: <2/0/1/1> = 2
Element: <2/0/2/2> = 3
Element: <2/1/0/0> = 1
Element: <2/1/1/1> = 2
Element: <2/1/2/2> = 3
Cheerio!
h["cool"].keys
to then iterate the tree would be
h["cool"].keys.each |outer| { h["cool"][outer].each { |inner| puts inner }}
It really depends on what you're trying to do (nowhere near enough information in the question), but if you need to dive in three or more levels into a Hash
, you may very well want a recursive tree traversal algorithm:
def hash_traverse(hash)
result = ""
for key, value in hash
result << key.to_s + ":\n"
if !value.kind_of?(Hash)
result << " " + value.to_s + "\n"
else
result << hash_traverse(value).gsub(/^/, " ")
end
end
return result
end
Are you sure a Hash
is the best data structure for what you're trying to do?
精彩评论