# Newbie question about sets

**URL:** <https://www.ruby-forum.com/t/newbie-question-about-sets/82514>\
**Category:** Ruby\
**Created:** [January 19, 2007, 4:31pm UTC](https://www.ruby-forum.com/t/newbie-question-about-sets/82514 "2007-01-19T16:31:00Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![jasonmorrison](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/47e85d/32.png) [@jasonmorrison](https://www.ruby-forum.com/u/jasonmorrison)\
**Post date:** [January 19, 2007, 4:31pm UTC](https://www.ruby-forum.com/t/newbie-question-about-sets/82514/1 "2007-01-19T16:31:00Z")

</div>

I’m just curious if there’s any way to duplicate values in a set. After  
quiz 108, I modified my submission so that it was a fully functional  
game.  
I then passed around my finished program to some of my coworkers who are  
interested in ruby. After a few days, someone came back to me with a  
bug,  
and this appears to be the root cause of that bug.

irb(main):001:0\> target = “stuff”  
=\> “stuff”  
irb(main):002:0\> a = target.split(//).sort  
=\> [“f”, “f”, “s”, “t”, “u”]  
irb(main):003:0\> require ‘Set’  
=\> true  
irb(main):004:0\> s1 = Set.new(a)  
=\> #\<Set: {“f”, “s”, “t”, “u”}\>

As it stands, if the word ffffuuuuussssstttt existed, it would be  
considered  
a subset of a. How do you avoid this using sets?

---

<div class="post-metadata">

**Author:** ![jasonmorrison](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/47e85d/32.png) [@jasonmorrison](https://www.ruby-forum.com/u/jasonmorrison)\
**Post date:** [September 25, 2007, 10:36pm UTC](https://www.ruby-forum.com/t/newbie-question-about-sets/82514/2 "2007-09-25T22:36:59Z")

</div>

On Jan 15, 2007, at 1:57 PM, Jason M. wrote:

> Set implements a collection of unordered values with no duplicates.

Yes, that implements sets as defined in math. What you wanted is  
called “multiset”[\*], though in my degree I never saw any of those  
even mentioned.

– fxn

[\*] [Multiset -- from Wolfram MathWorld](http://mathworld.wolfram.com/Multiset.html)

---

<div class="post-metadata">

**Author:** ![jasonmorrison](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/47e85d/32.png) [@jasonmorrison](https://www.ruby-forum.com/u/jasonmorrison)\
**Post date:** [September 25, 2007, 10:37pm UTC](https://www.ruby-forum.com/t/newbie-question-about-sets/82514/3 "2007-09-25T22:37:23Z")

</div>

You shouldn’t really have to avoid this. The 6 letter word should be 6  
unique letters, otherwise how would there be 6 letters for the user to  
guess?

Dan

---

<div class="post-metadata">

**Author:** ![jasonmorrison](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/47e85d/32.png) [@jasonmorrison](https://www.ruby-forum.com/u/jasonmorrison)\
**Post date:** [September 25, 2007, 10:41pm UTC](https://www.ruby-forum.com/t/newbie-question-about-sets/82514/4 "2007-09-25T22:41:22Z")

</div>

On 1/15/07, Jason M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> irb(main):002:0\> a = target.split(//).sort  
> =\> [“f”, “f”, “s”, “t”, “u”]  
> irb(main):003:0\> require ‘Set’  
> =\> true  
> irb(main):004:0\> s1 = Set.new(a)  
> =\> #\<Set: {“f”, “s”, “t”, “u”}\>
> 
> As it stands, if the word ffffuuuuussssstttt existed, it would be  
> considered  
> a subset of a. How do you avoid this using sets?

Doh! first line of ri Set told me what I needed to know - that it’s not  
really possible.

Set implements a collection of unordered values with no duplicates.

---

<div class="post-metadata">

**Author:** ![jasonmorrison](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/47e85d/32.png) [@jasonmorrison](https://www.ruby-forum.com/u/jasonmorrison)\
**Post date:** [September 25, 2007, 10:44pm UTC](https://www.ruby-forum.com/t/newbie-question-about-sets/82514/5 "2007-09-25T22:44:25Z")

</div>

On 15.01.2007 14:36, Stefano Z. wrote:

> reach 0.  
> def initialize  
> @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

---

<div class="post-metadata">

**Author:** ![jasonmorrison](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/47e85d/32.png) [@jasonmorrison](https://www.ruby-forum.com/u/jasonmorrison)\
**Post date:** [September 25, 2007, 10:47pm UTC](https://www.ruby-forum.com/t/newbie-question-about-sets/82514/6 "2007-09-25T22:47:36Z")

</div>

On 1/15/07, Daniel F. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> You shouldn’t really have to avoid this. The 6 letter word should be 6  
> unique letters, otherwise how would there be 6 letters for the user to  
> guess?
> 
> Dan

So here’s what one of my coworkers sent to me:

Current score: 5900  
Incorrect: 2  
EIINSS  
17 possible words left!  
word:inn  
Current score: 5990  
Incorrect: 0

In this case, “inn”.split(//).sort would be s2, and @s1 would be  
EIINSS.split(//). N did not appear in the word list twice, but the part  
of  
my code that said if s2.subset?(@s1) returned true because the actual  
values  
compared were  
s2= Set: {“i”, “n”}  
@s1 = Set: {“e”, “i”, “n”, “s”}  
s2 is in fact a subset of @s1, but if Set allowed for multiple  
non-unique  
values (i.e. {“i”, “n”, “n”}) then it wouldn’t have been the case.

In the end, it doesn’t matter… I was just looking to make a game for  
me  
and my coworkers. Tech support is boring. But maybe finding all the  
words  
in seisin is more boring. I don’t know.

---

<div class="post-metadata">

**Author:** ![jasonmorrison](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/47e85d/32.png) [@jasonmorrison](https://www.ruby-forum.com/u/jasonmorrison)\
**Post date:** [September 25, 2007, 10:47pm UTC](https://www.ruby-forum.com/t/newbie-question-about-sets/82514/7 "2007-09-25T22:47:45Z")

</div>

Answering to myself …

On Mon, Jan 15, 2007 at 10:29:11PM +0900, Stefano Z. 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

---

<div class="post-metadata">

**Author:** ![jasonmorrison](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/47e85d/32.png) [@jasonmorrison](https://www.ruby-forum.com/u/jasonmorrison)\
**Post date:** [September 25, 2007, 10:50pm UTC](https://www.ruby-forum.com/t/newbie-question-about-sets/82514/8 "2007-09-25T22:50:40Z")

</div>

On Mon, Jan 15, 2007 at 10:07:47PM +0900, Xavier N. wrote:

> Yes, that implements sets as defined in math. What you wanted is  
> called “multiset”[\*], though in my degree I never saw any of those  
> even mentioned.

I guess one can build them by herself on the following lines:

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)  
super(o)  
@arity[o] -= 1  
@arity.delete o if @arity[o] == 0  
end  
end

but beware that the above is newbie’s code (and also utterly simplified  
…) 🙂

And by the way, why the above class does not work properly with \<\<  
(which is an alias for add according to my set.rb) while it works  
properly with add?

E.g.

irb(main):019:0\> m=MultiSet.new  
=\> #\<MultiSet: {}\>  
irb(main):020:0\> m.add 1  
=\> 1  
irb(main):021:0\> m.add 1  
=\> 2  
irb(main):022:0\> m.arity[1]  
=\> 2 # so far so good

irb(main):023:0\> m \<\< 2  
=\> #\<MultiSet: {1, 2}\>  
irb(main):024:0\> m \<\< 2  
=\> #\<MultiSet: {1, 2}\>  
irb(main):025:0\> m.arity[2]  
=\> nil # aargh, do I need to alias again in  
# derived classes? that’s too bad …

TIA,  
Cheers.
