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