From: "David A. Black" Date: 2009-08-28T20:12:11+09:00 Subject: Re: data sctructure --1926193751-336443677-1251457854=:19712 Content-Type: MULTIPART/MIXED; BOUNDARY="1926193751-336443677-1251457854=:19712" This message is in MIME format. The first part should be readable text, while the remaining parts are likely unreadable without MIME-aware tools. --1926193751-336443677-1251457854=:19712 Content-Type: TEXT/PLAIN; charset=EUC-KR; format=flowed Content-Transfer-Encoding: 8BIT Hi -- On Fri, 28 Aug 2009, Robert Klemme wrote: > 2009/8/28 David A. Black : >> This message is in MIME format. The first part should be readable text, >> while the remaining parts are likely unreadable without MIME-aware tools. >> >> Hi -- >> >> On Fri, 28 Aug 2009, Juliano 層硲 wrote: >> >>> Hello guys. >>> >>> I've just started using ruby and I come from Python... I'm still >>> learning to think the Ruby way... >>> Of course, any beginning is hard, but even so I've been having a lot >>> of fun learning Ruby. >> >> Welcome! I'm glad you're enjoying it. >> >>> The problem is that I still don't know much about the tons of methods >>> and I'm maybe letting something pass through my fingers. >>> >>> My problem is this: >>> I have to read a file and set up a data structure of embedded >>> dictionaries. In Python I can easily do that by means of >>> "dict.defaultdict()", but I didn't understand how to do that in >>> Ruby... I finally came up with the following: >>> >>> def preprocess(lines) >>> d = {} >>> lines.each do |line| >>> c, s, fc, fl = line.split("\t") >>> if !d.has_key? c >>> d[c] = {} >>> end >>> if !d[c].has_key? s >>> d[c][s] = {} >>> end >>> if !d[c][s].has_key? fc >>> d[c][s][fc] = [] >>> end >>> d[c][s][fc].push fl >>> end >>> return d >>> end >>> >>> My question is: Is there an easier way to do this in Ruby as it is in >>> Python? >> >> The idiom for conditional assignment in Ruby is ||= (or-equals). You >> could do this: >> >> def preprocess(lines) >> d = {} >> lines.each do |line| >> c, s, fc, fl = line.split("\t") >> d[c] ||= {} >> d[c][s] ||= {} >> d[c][s][fc] ||= [] >> d[c][s][fc].push fl >> end >> return d >> end >> >> The only thing is, in cases where you want false or nil to be a hash >> value, ||= will over-eagerly do the assignment. But that's not the >> case here. >> >> There are also ways to set the default behavior of hashes, but I think >> the above is probably the most direct way to do what you want. > > You mean something like the more involved > > def preprocess(lines) > d = Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)} > > lines.each do |line| > c, s, fc, fl = line.split("\t") > (d[c][s][fc] ||= []) << fl > end > > d > end Yes, that's what I meant. David -- David A. Black / Ruby Power and Light, LLC / http://www.rubypal.com Q: What's the best way to get a really solid knowledge of Ruby? A: Come to our Ruby training in Edison, New Jersey, September 14-17! Instructors: David A. Black and Erik Kastner More info and registration: http://rubyurl.com/vmzN --1926193751-336443677-1251457854=:19712-- --1926193751-336443677-1251457854=:19712--