SwiftのCollectionとRangeを組み合わせて使いこなし術

SwiftのCollectionとRangeを組み合わせて使いこなし術

Table of Contents

SwiftのCollectionはSetやArray、Dictionaryの土台となる重要なポジションです。
今回はSupporting Types - Apple Developer Documentationにあるサポート機能について使えそうなものがないかを調べてまとめました。

CollectionとRangeの組み合わせ

Collectionには範囲取得する機能があります。
範囲を表す型は、Rangeを使います。
例えば、下のコードを見かけた人は多いと思います。

let values = [1, 2, 3, 4]
let partial = values[1...2]
print(partial) // [2, 3]

実はこれ以外の範囲指定方法がCollectionには用意されています。

  • PartialRangeUpTo: 上限のみ(上限未満)
  • PartialRangeThrough: 上限のみ(上限以下)
  • PartialRangeFrom: 下限のみ
  • UnboundedRange_: 上限下限なし

PartialRangeUpTo: 上限のみ(上限未満)

上限値のみが指定された範囲型です。
下限は無制限となります。
そのためcontainsメソッドで範囲内判定を確認するとマイナスでもtrueを返します。

let upToFive = ..<5.0
print(type(of: upToFive)) // PartialRangeUpTo<Double>
print(upToFive.contains(3.14)) // true
print(upToFive.contains(5.0)) // false
print(upToFive.contains(5.1)) // false
print(upToFive.contains(-0.1)) // true

これをCollectionの範囲指定として使えます。

let numbers = [4, 2, 3, 4, 5]
print(numbers[..<3]) // [4, 2, 3]

ちなみにパターンマッチング演算子(~=)が用意されているので下記2つは同じ意味です。

print(..<3 ~= 2) // true
print((..<3).contains(2)) // true

PartialRangeThrough: 上限のみ(上限以下)

PartialRangeUpToと同じですが、こちらは上限値も範囲に含めます。

let throughFive = ...5.0
print(throughFive.contains(3.14)) // true
print(throughFive.contains(5.0)) // true
print(throughFive.contains(5.1)) // false
print(throughFive.contains(-0.1)) // true

これをCollectionの範囲指定として使えます。

let numbers = [4, 2, 3, 4, 5]
print(numbers[...3]) // [4, 2, 3, 4]

PartialRangeFrom: 下限のみ

下限値のみが指定された範囲型です。
上限は無制限となります。
containsメソッドで確認すると下記のようになります。

let atLeastFive = 5...
print(atLeastFive.contains(4)) // false
print(atLeastFive.contains(5)) // true
print(atLeastFive.contains(Int.max)) // true

これをCollectionの範囲指定として使えます。

let numbers = [4, 2, 3, 4, 5]
print(numbers[3...]) // [4, 5]

UnboundedRange_: 上限下限なし

これはレアケースな気がしますが、上限も下限も無制限の指定方法があります。

let numbers = [4, 2, 3, 4, 5]
print(numbers[...]) // [4, 2, 3, 4, 5]

Collection+Rangeまとめ

出てきた書き方を下記にまとめます。

let numbers = [4, 2, 3, 4, 5]
print(numbers[..<3])
print(numbers[...3])
print(numbers[3...])
print(numbers[...])
zip(numbers, 999...).forEach { (v1, v2) in
    print(v1, v2)
}
print(..<3 ~= 2)

Collectionの範囲取得で 0..<3 のような書き方をショートハンドのように省略できるようになります。
使い所は広くはありませんが、知っておくとライブラリコードで突然出てきても落ち着いて読み進めることができます。

このエントリーをはてなブックマークに追加