配列同士の比較はSetを使うと順序の考慮が不要になる

バリデーションの実装で配列同士の比較で要素の順序を考慮せず比較する方法としてSetを教えてもらいました。

結論

Rubyでは集合を表すSetを使うことで配列の順序の考慮が不要になる。

class Set (Ruby 3.2 リファレンスマニュアル)

Set(集合)とは?

RubyのSetは一意な値の集合を表現するためのデータ構造です。 配列やハッシュと同じオブジェクトの集合を表すものですが以下のような特徴があります。

  • 要素が重複しない
  • 要素の順序は保持されない

配列、ハッシュとの違い

  • 配列との違い

    • 重複要素の扱い
      • 配列: 複数持てる
      • 集合: 一意な要素のみ
    • 順序の扱い
      • 配列: 保持する
      • 集合: 保持しない
  • ハッシュとの違い

    • 要素の組み合わせ
      • ハッシュ: キーと値の組み合わせ
      • 集合: 単一の要素の集合
    • 一意性の保証
      • ハッシュ: キーが一意である必要がある
      • 集合: 要素自体が一意である必要がある

ざっくりですが集合は「そのオブジェクトの集まりが順序を考慮せず、一意性を保証したい」といった場合に活用できそうです。

コンソールで動かしてみる

集合のオブジェクトはSet.new(集合の初期要素) で作成できる。 集合の初期要素としては以下が該当する。

  • 配列
  • ハッシュ

たぶん他にもあるっぽい。

library set (Ruby 3.2 リファレンスマニュアル)

require 'set'
Set.new()
=> #<Set: {}> # 空の集合
Set.new([1,2])
=> #<Set: {1, 2}> # 配列を元にした集合
Set.new({a: 1, b: 2})
=> #<Set: {[:a, 1], [:b, 2]}> # ハッシュを元にした集合

例) 配列は順序を保持するが、集合は保持しない

# 配列
array_1 = [1,2]
=> [1, 2]
array_2 = [2,1]
=> [2, 1]
array_1 == array_2
=> false # 要素の順序を保持されるのでfalse

# 集合
require 'set'
set_1 = Set.new([1,2])
=> #<Set: {1, 2}>
set_2 = Set.new([2,1])
=> #<Set: {2, 1}>
set_1 == set_2
=> true # 要素の順序が保持されないのでtrue

感想

Setの存在すら知らなかったので良い機会になった。 Rubyは便利だなーと改めて感じた。

参照

class Set (Ruby 3.2 リファレンスマニュアル) library set (Ruby 3.2 リファレンスマニュアル)