Ruby でセットオブジェクト(重複する値を許さないコレクション)を生成するには、標準ライブラリに含まれている Set
クラスを使用します。
配列やハッシュを扱うときは、Ruby の構文として []
や {}
を使用できましたが、セットに関しては単純なクラスとして提供されています。
Set
オブジェクトを生成するには、コンストラクタの Set.new()
を使用します。
require 'set'
s = Set.new
p s #=> #<Set: {}>
Enumerable
なオブジェクト、例えば配列を Set.new()
に渡して Set
オブジェクトを生成することできます。
この際、重複した要素は削除されます。
require 'set'
s = Set.new([3, 1, 2, 1])
p s #=> #<Set: {3, 1, 2}>
s = Set.new(1..5)
p s #=> #<Set: {1, 2, 3, 4, 5}>
Enumerable
には to_set()
メソッドが用意されているので、これを呼び出して Set
オブジェクトを生成することもできます。
s = ['aaa', 'bbb', 'ccc', 'bbb'].to_set
p s #=> #<Set: {"aaa", "bbb", "ccc"}>
Set[]
を使用すると、任意の数の値を渡して Set
オブジェクトを生成することができます。
Set.new()
で配列オブジェクトを渡すのと見た目は似てますが、こちらは配列オブジェクトを 1 つだけ渡しているわけではなく、複数の値を 1 ずつ引数として渡しています。
s = Set[3, 1, 2, 1]
p s #=> #<Set: {3, 1, 2}>
既存のセットオブジェクトに 1 つの要素を追加するには add
メソッド、あるいは <<
演算子を使用します。
require 'set'
s = Set.new
s.add(1)
s << 2
s.add(1)
p s #=> #<Set: {1, 2}>
複数の要素を一度に追加したいときは、merge
メソッドを使用してください(add
メソッドに配列を渡してしまうと、1 つの配列要素としてセットに追加されてしまいます)。
require 'set'
s = Set[1, 2]
s.merge([2, 3])
s.merge([3, 4])
p s #=> #<Set: {1, 2, 3, 4}>
既存のセットオブジェクトから 1 つの要素を取り除くには、delete
メソッドを使用します。
存在しない要素を取り除こうとした場合は何も起こりません。
require 'set'
s = Set[1, 2, 3, 4]
s.delete(1)
s.delete(3)
s.delete(1)
p s #=> #<Set: {2, 4}>
複数の要素をまとめて取り除くには、subtract
メソッドを使用してください(delete
メソッドに配列を渡してしまうと、配列をセットから取り除こうとしてしまいます)。
require 'set'
s = Set[1, 2, 3, 4]
s.subtract([1, 2]) # 1 と 2 を取り除く
s.delete([3, 4]) # [3, 4] という配列は含まれていないので何もしない
p s #=> #<Set: {3, 4}>
Set#include?
は、指定した値がその Set
に含まれている場合に true
を返します。
require 'set'
s = Set['aaa', 'bbb', 'ccc']
puts s.include?('aaa') #=> true
puts s.include?('ddd') #=> false
Set#subset?
(あるいは <=
演算子)を使用すると、あるセットの要素が、もう一方のセットにすべて含まれているかどうかを調べることができます。
require 'set'
s1 = Set[1, 2, 3, 4]
s2 = Set[2, 4]
p s1 <= s2 #=> false
p s1.subset?(s2) #=> false
p s2 <= s1 #=> true
p s2.subset?(s1) #=> true
subset?
と似たメソッドとして proper_subset?
(あるいは <
演算子)がありますが、こちらは 2 つのセットの要素が完全に一致する場合に false
を返すという特殊な振る舞いをします。
通常は subset?
の方を使うと覚えておけばよいでしょう。
require 'set'
s1 = Set[1, 2]
s2 = Set[1, 2]
s3 = Set[1, 2, 3]
p s1 < s2 #=> false
p s1 < s3 #=> true
p s1.proper_subset?(s2) #=> false
p s1.proper_subset?(s3) #=> true
+
演算子、あるいは |
演算子、あるいは union
メソッドを用いることで、セット同士の和集合(いずれかのセットに含まれている要素からなる集合)を求めることができます。
require 'set'
s1 = Set[1, 2, 3, 4]
s2 = Set[3, 4, 5, 6]
p s1 + s2 #=> #<Set: {1, 2, 3, 4, 5, 6}>
p s1 | s2 #=> #<Set: {1, 2, 3, 4, 5, 6}>
p s1.union(s2) #=> #<Set: {1, 2, 3, 4, 5, 6}>
&
演算子を用いることで、セット同士の共通集合(両方のセットに含まれている要素からなる集合)を求めることができます。
require 'set'
s1 = Set[1, 2, 3, 4]
s2 = Set[3, 4, 5, 6]
p s1 & s2 #=> #<Set: {3, 4}>
^
演算子を用いることで、いずれかのセットにしか含まれていない要素を調べることができます。
つまり、要素の排他的論理和 (XOR) です。
require 'set'
s1 = Set[1, 2, 3, 4]
s2 = Set[3, 4, 5, 6]
p s1 ^ s2 #=> #<Set: {5, 6, 1, 2}>
-
演算子、あるいは difference
メソッドを用いることで、左辺に指定したセットにしか存在しない要素を調べることができます。
左辺と右辺の値を入れ替えると結果が変わってくることに注意してください。
require 'set'
s1 = Set[1, 2, 3, 4]
s2 = Set[3, 4, 5, 6]
p s1 - s2 #=> #<Set: {1, 2}>
p s2 - s1 #=> #<Set: {5, 6}>
言い換えると、「左辺のセットから右辺で指定した要素を削除したセットを作成する」とも言えます。
ちなみに、セットではなく配列でもこのような演算を行うことができます。
arr1 = [1, 2, 3, 4, 1, 2, 3, 4]
arr2 = [2, 3]
p arr1 - arr2 #=> [1, 4, 1, 4]