Swiftで遊ぼう! on Hatena

あしたさぬきblogでやってた初心者オヤジのiOSプログラミング奮闘記がHatenaに来ました

Swiftで遊ぼう! - 361 - Swift 3.0:Set

2016年11月1日:Swift 3向けに変更
2016年7月5日:改訂

プロジェクト「Sections」に取り組んでいるのですが、コードの内容で分からないところがあるので、「The Swift Programming Language」を読んでいます。Swift1.2とSwift2.0と少し変化がありました。そして2016年7月の段階のSwift 3.0でも修正があるので変更します。

Set

同型の異なる値のコレクションですが並び順は考慮されません。Array型とよく似ているのですが、Objective-CAPI(フレームワーク)を利用するために存在するので、Objective-CNSSetと互換性があります。

hashable(ハッシュ可能)

ハッシュ値(hash value)」とは元のデータから一定の計算により求められた「規則性の無い固定長の値」だそうです。この「一定の計算」のことを「ハッシュ関数」と呼ぶようですが、ハッシュ値から元のデータを復元することはできません。情報内容を欠損させる計算過程を取るので不可逆になります。ということで、同一の固定長の値(ハッシュ値)を持つことのできる元のデータ型をhashable(ハッシュ可能)といいます。

Setで設定できる「型」はハッシュ可能でなければならないルールがあります。そしてハッシュ値は「Int型」になります。

Swiftに用意されている標準的な「型」、String、Int、Double、そしてBoolなど、すべてハッシュ可能なんで、Setの型やDictionaryの「key」に使えます。

Set型のシンタックス

var a: Set<Element> = []
// これが基本形で、<Element>はAnyObjectです。
// そして以下のように宣言できます。
// 宣言時に「Set」を省略することができません。

var b: Set<String> = []
b = ["one", "Two"]

SetもArrayと同様で色々編集できます。

var c: Set = ["Six", "Seven", "Eight", "Nine"]

for element in c {
    print("\(element)")
}

// Six
// Nine
// Eight
// Seven
// 並びは考慮されません。

for element in c.sorted() {
    print("\(element)")
}

// Eight
// Nine
// Seven
// Six
// 並び順はアルファベット順にソートされます。

変更ではないのですが、remove()の扱いを間違えないようにしないといけませんね。

var d: Set = ["One", "Two", "Three"]

d.count
/ /3

if !d.isEmpty {
    print("I have values.")
}

// I have valurs.

d.insert("Four")
// 加わります。

var r = d.remove("One")
// remove()メソッドで取りだしは、
// オプショナル扱いなので、rには
// Optional"One"が入ります!

r ?? "NoValue"
// ということでこうすれば、r = "One"になります。

基本オペレーション

Setには色々なオペレーションがあり覚えておく必要があるでしょう。なかなか覚えられないんですけどね。

// 上からの続きで「c」に新しいコレクションを設定させます。
c = ["Four", "Five", "Six", "Seven"]
// 「d」にも新しいコレクションを設定します。
d = ["Six", "Seven", "Eight", "Nine"]

f:id:yataiblue:20160706152433j:plain

c.intersection(d)
// {"Six", "Seven"}

c.symmetricDifference(d)
// {"Nine", "Four", "Eight", "Five"}

c.union(d)
// {"Six", "Four", "Nine", "Five", "Eight", "Seven"}

c.subtract(d)
// {"Four", "Five"}

ということです。

Setの項目と等式

次のイメージの3つのSet、「a」「b」「c」を使って等式の説明をします。
f:id:yataiblue:20161101164313j:plain

  • ==は2つのSetの中身が全く同じなら「true 」を返します。
  • isSubset(of:)は、of引数で与えたSetのサブセットであれば「true」を返します。
  • isSuperset(of:)は、of引数で与えたSetのスーパーセットであれば「true」を返します。
  • isStrictSubset(of:)/isStrictSuperset(of:)は、of引数で与えられたサブセット/スーパーセットで、決して同じではないなら「true」を返します。
  • isDisjoint(with:)は、2つのSetに交わりが無いと「true」を返します。
let houseAnimals: Set = ["🐶", "🐱"]
let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]
let cityAnimals: Set = ["🐦", "🐭"]

let copyAnimals: Set = houseAnimals

houseAnimals == copyAnimals
// true
houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true

これだけです。