From: Robert Klemme Date: 2007-01-16T00:50:07+09:00 Subject: Re: newbie question about sets On 15.01.2007 14:36, Stefano Zacchiroli wrote: > Answering to myself ... > > On Mon, Jan 15, 2007 at 10:29:11PM +0900, Stefano Zacchiroli wrote: >> def delete(o) >> super(o) >> @arity[o] -= 1 >> @arity.delete o if @arity[o] == 0 >> end > > The above is of course wrong, elements get remove before their arity > reach 0. > >> => nil # aargh, do I need to alias again in >> # derived classes? that's too bad ... > > Apparently so, alias makes a *copy* of the method :( > > Here is a better version: > > require 'set' > class MultiSet < Set > def initialize > super > @arity = {} > end > attr_reader :arity > def add(o) > super(o) > @arity[o] = 0 unless @arity.member? o > @arity[o] += 1 > end > def delete(o) > @arity[o] -= 1 > if @arity[o] == 0 > super(o) > @arity.delete o > end > end > alias << add > end > You can as well use a Hash as multi set: irb(main):001:0> multi_set = Hash.new 0 => {} irb(main):002:0> multi_set['foo'] += 1 => 1 irb(main):003:0> multi_set => {"foo"=>1} irb(main):004:0> multi_set['foo'] += 1 => 2 irb(main):005:0> multi_set => {"foo"=>2} irb(main):006:0> multi_set['bar'] += 1 => 1 irb(main):007:0> multi_set['bar'] => 1 irb(main):008:0> multi_set['foo'] => 2 irb(main):009:0> multi_set => {"foo"=>2, "bar"=>1} irb(main):010:0> multi_set['foo'] -= 1 => 1 irb(main):011:0> multi_set => {"foo"=>1, "bar"=>1} irb(main):012:0> multi_set['xxx'] => 0 Of course this does not prevent values other than numbers as well as negative numbers. Ah, and btw, I'm not sure whether it's a good idea to have a MultiSet class inherit Set: after all Set /is (the special case of) a/ MultiSet - not the other way round. Kind regards robert