浏览 3675 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-03-27
改编成一个rubyquiz。要求:扩展Hash类,写一个each_component方法,让下面的代码可以运行出期望的结果来。 class Sneaker def initialize(attributes) @brand, @size, @store = attributes[:brand], attributes[:size], attributes[:store] end def to_s "#{@brand} sneakers of #{@size}in from #{@store} store." end end sneaker_combination = { :brand => [:adidas, :nike], :size => [38, 40, 42], :store => :shanghai } sneaker_combination.each_component do |sneaker| # sneaker_sample.should.be({:brand => :nike, :size => 38, :store => :shanghai}) puts Sneaker.new(sneaker) end # should print: # adidas sneakers of 38in from shanghai store. # adidas sneakers of 40in from shanghai store. # adidas sneakers of 42in from shanghai store. # nike sneakers of 38in from shanghai store. # nike sneakers of 40in from shanghai store. # nike sneakers of 42in from shanghai store. 过几天贴出我的解法。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-03-27
def change_hash(hash) brand=[] size=[] store=[] hash.each do |key,value| if key.to_s.eql? "brand" value.each { |br| brand << br } end if key.to_s.eql? "size" value.each { |si| size << si } end if key.to_s.eql? "store" value.each { |st| store << st } end end brand.each do |br1| size.each do |si1| store.each do |st1| puts "#{br1} sneakers of #{si1}in from #{st1} store." end end end end sneaker_combination = { :brand => ["adidas", "nike"], :size => [38, 40, 42], :store => ["shanghai"] } change_hash(sneaker_combination) 我先来一个,不知道对还是不对,但是能得到预期的结果 #adidas sneakers of 38in from shanghai store. #adidas sneakers of 40in from shanghai store. #adidas sneakers of 42in from shanghai store. #nike sneakers of 38in from shanghai store. #nike sneakers of 40in from shanghai store. #nike sneakers of 42in from shanghai store. |
|
返回顶楼 | |
发表时间:2008-03-27
有点眼熟,可以抽象为多维数组组合吧,以前写的:
data = [['a','b'],['c','d','e'],['f','g','h','i']] # or more items def combine(a, b) if b.is_a?(Array) && !b.empty? tmp = [] c = b.shift a.each do |aa| c.each do |cc| if aa.is_a?(Array) tmp.push aa.clone.push(cc) # may be a ruby bug: must use clone else tmp.push [aa, cc] end end end if !b.empty? return combine(tmp, b) else return tmp end end end p "result:" result = combine(data.shift, data) p result p result.size ------------- "result:"[["a", "c", "f"], ["a", "c", "g"], ["a", "c", "h"], ["a", "c", "i"], ["a", "d", "f"], ["a", "d", "g"], ["a", "d", "h"], ["a", "d", "i"], ["a", "e", "f"], ["a", "e", "g"], ["a", "e", "h"], ["a", "e", "i"], ["b", "c", "f"], ["b", "c", "g"], ["b", "c", "h"], ["b", "c", "i"], ["b", "d", "f"], ["b", "d", "g"], ["b", "d", "h"], ["b", "d", "i"], ["b", "e", "f"], ["b", "e", "g"], ["b", "e", "h"], ["b", "e", "i"]] 24 |
|
返回顶楼 | |
发表时间:2008-03-27
来个暴力计算的,让大家拍砖:
module HashExtendsion def each_component hash_size = self.values.select{|i|i.class == Array}.inject(1){|sum,i|sum*i.size} hash = self.map{|k,v|{k=>(v.class == Array)?(v*(hash_size/v.size)).sort_by{|i|i.to_s}:[v]*hash_size}}.inject({}){|sum,i|sum.merge(i)} hash_keys = self.keys (0...hash_size).each{|index|yield Hash[*hash_keys.map{|i|[i,hash[i][index]]}.flatten] if block_given?} end end class Hash include HashExtendsion end |
|
返回顶楼 | |
发表时间:2008-03-27
@rainchen
haha... 是我问过你这个问题。 |
|
返回顶楼 | |
发表时间:2008-03-27
为什么我这样写 不行啊?
def add_method(c,m,&b) c.class_eval { define_method(m,&b) } end add_method(Hash, :each_component) { hash_size = self.values.select{|i|i.class == Array}.inject(1){|sum,i|sum*i.size} hash = self.map{|k,v|{k=>(v.class == Array)?(v*(hash_size/v.size)).sort_by{|i|i.to_s}:[v]*hash_size}}.inject({}){|sum,i|sum.merge(i)} hash_keys = self.keys (0...hash_size).each{|index|yield Hash[*hash_keys.map{|i|[i,hash[i][index]]}.flatten] if block_given?} } |
|
返回顶楼 | |
发表时间:2008-03-28
lgn21st 写道 来个暴力计算的,让大家拍砖: module HashExtendsion def each_component hash_size = self.values.select{|i|i.class == Array}.inject(1){|sum,i|sum*i.size} hash = self.map{|k,v|{k=>(v.class == Array)?(v*(hash_size/v.size)).sort_by{|i|i.to_s}:[v]*hash_size}}.inject({}){|sum,i|sum.merge(i)} hash_keys = self.keys (0...hash_size).each{|index|yield Hash[*hash_keys.map{|i|[i,hash[i][index]]}.flatten] if block_given?} end end class Hash include HashExtendsion end 修正,计算hash的时候不应该排序,否则结果不对 class Hash def each_component hash_size = self.values.select{|i|i.class == Array}.inject(1){|sum,i|sum*i.size} hash = self.map{|k,v|{k=>(v.class == Array)?(v*(hash_size/v.size)):[v]*hash_size}}.inject({}){|sum,i|sum.merge(i)} hash_keys = self.keys (0...hash_size).each{|index|yield Hash[*hash_keys.map{|i|[i,hash[i][index]]}.flatten] if block_given?} end end |
|
返回顶楼 | |
发表时间:2008-03-30
@不是流氓 可能是我没说清楚,这个each_component是要解决一个通用问题的,所以brand,size这些指定的key要被抽象出来。
@rainchen 递归是个好办法,算法很容易读懂。我按照rainchen的思路,想写一个针对Hash的递归,虽然Hash也有shift,但是无法完成。看来这个算法只适合Array,Hash的话,要先把values组合成一个array,运行后再把结果转回Hash。 @yangtao309 c.class_eval的参数是个字符串,所以起码里面要写成define_method(#{m}),但是这样也不对,还要好好研究一下define_method的定义:http://www.ruby-doc.org/core/classes/Module.html#M001677 。 @lgn21st 这段代码很短很有ruby味,lgn21st功力深厚,不过考虑不周。下面这种2×2的情况结果就不对了。 sneaker_combination = { :brand => [:adidas, :nike], :size => [38, 40], :store => :shanghai } sneaker_combination.each_component do |sneaker| puts Sneaker.new(sneaker) end # 输出结果有重复了 # adidas sneakers of 38in from shanghai store. # nike sneakers of 40in from shanghai store. # adidas sneakers of 38in from shanghai store. # nike sneakers of 40in from shanghai store. |
|
返回顶楼 | |
发表时间:2008-03-30
我的解法,参考了lgn21st的ruby风格:
class Hash def each_component # dup a working hash hash, batch_size = self.dup, 1 hash.each {|k,v| hash[k] = [v] unless v.is_a?(Array); batch_size *= hash[k].size } # build matrix before_size = 1 hash.each do |k, v| after_size = batch_size / before_size / v.size hash[k] = build_matrix(hash[k], before_size, after_size) before_size *= v.size end # iterator (0...batch_size).each do |index| yield Hash[*hash.keys.map{|k|[k,hash[k][index]]}.flatten] if block_given? end end private def build_matrix(array, before_size, after_size) (array.collect{|item| Array.new(after_size, item) } * before_size).flatten end end |
|
返回顶楼 | |
发表时间:2008-03-30
yangtao309 写道 为什么我这样写 不行啊?
def add_method(c,m,&b) c.class_eval { define_method(m,&b) } end add_method(Hash, :each_component) { hash_size = self.values.select{|i|i.class == Array}.inject(1){|sum,i|sum*i.size} hash = self.map{|k,v|{k=>(v.class == Array)?(v*(hash_size/v.size)).sort_by{|i|i.to_s}:[v]*hash_size}}.inject({}){|sum,i|sum.merge(i)} hash_keys = self.keys (0...hash_size).each{|index|yield Hash[*hash_keys.map{|i|[i,hash[i][index]]}.flatten] if block_given?} } 下面这样可以了~~ 但是还是不明白上面为什么不行 def add_method(c,m) c.class_eval{ define_method(m,instance_method(m)) } end def each_component hash_size = self.values.select{|i|i.class == Array}.inject(1){|sum,i|sum*i.size} hash = self.map{|k,v|{k=>(v.class == Array)?(v*(hash_size/v.size)).sort_by{|i|i.to_s}:[v]*hash_size}}.inject({}){|sum,i|sum.merge(i)} hash_keys = self.keys (0...hash_size).each{|index|yield Hash[*hash_keys.map{|i|[i,hash[i][index]]}.flatten] if block_given?} end add_method(Hash, :each_component) |
|
返回顶楼 | |