Matthew Moss ha scritto: > -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- > > The three rules of Ruby Quiz 2: > > 1. Please do not post any solutions or spoiler discussion for this > quiz until 48 hours have passed from the time on this message. > > 2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A > permanent, new website is in the works for Ruby Quiz 2. Until then, > please visit the temporary website at > > <http://splatbang.com/rubyquiz/>. > > 3. Enjoy! > > Suggestion: A [QUIZ] in the subject of emails about the problem > helps everyone on Ruby Talk follow the discussion. Please reply to > the original quiz message, if you can. > > -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- > > ## Records and Arrays (#170) > > In a typical application, you might use what is commonly referred to > as an "array of records." Essentially, this is a single array > containing multiple objects that represent the same kind of structured > data, either as defined class or OpenStruct instances. Take, for > example, this bit of code that reads in some data regarding people: > their names, ages and favorite colors. > > require 'ostruct' > data = [] > File.open("data.txt").each do |line| > name, age, color = line.chomp.split(/,/) > d = OpenStruct.new > d.name = name > d.age = age > d.color = color > data << d > end > > The variable `records` is considered an "array of records", since to > get any particular piece of data, you must first access it as an array > (to get a particular record), then access it as a record (to get a > particular field). > > > p data[3].name > => "Matthew" > > > p data[3].age > => 36 > > However, at times, it is more convenient to store data as a "record of > arrays". Instead of one array containing multiple records, you have > one object (i.e. record) containing multiple, parallel arrays. Access > to data then is done first as a record, then as an array. > > > p data.name[3] > => "Matthew" > > > p data.age[3] > => 36 > > This sort of arrangement is useful when you want to access series of > data at a time. For example, if I have a graphing component that takes > two arrays -- one for the domain axis, and another for the range axis > -- a "record of arrays" will make accessing that data trivial. > > *Your task this week* is to define two functions that move data > between "array of records" storage and "record of arrays" storage. > > def aor_to_roa(arr) > # This method accepts an array of records, and > # should return a single record of arrays. > # > # This is your task! > end > > def roa_to_aor(rec) > # This method accepts a record of arrays, and > # should return a single array of records. > # > # This is also your task! > end > > You should make this work with [OpenStruct][1]; do not limit yourself > to the example records shown above. > > There are two, optional extra-credits for this week. > > 1. Extend these two functions to accept arbitrary classes. > > 2. As an alternative to these two functions, create an adapter class > that can wrap around "array of records" data to provide a "record of > arrays" interface without actually moving data about. > > > [1]: http://www.ruby-doc.org/stdlib/libdoc/ostruct/rdoc/classes/OpenStruct.html > > > > Hi all, here's my solution: require 'ostruct' def aor_to_roa(arr) hash = { } arr.each do |record| record.marshal_dump.each_key { |field| (hash[field] ||= []) << record.send(field) } end OpenStruct.new(hash) end def roa_to_aor(rec) result = [] rec.marshal_dump.each do |field, array| array.each_with_index { |value, index| (result[index] ||= OpenStruct.new).send("#{field}=", value) } end result end