便利(かも)な 演算子 をいくつか紹介します
1. 切り上げる整数除算演算子
普通の整数除算は切り捨て
ですが、切り上げる
整数除算演算子 /^
infix operator /^ : MultiplicationPrecedence
infix operator /^= : AssignmentPrecedence
@inlinable func /^ <T: FixedWidthInteger>(lhs: T, rhs: T) -> T { (lhs + (rhs - 1)) / rhs }
@inlinable func /^= <T: FixedWidthInteger>(lhs: inout T, rhs: T) { lhs = (lhs + (rhs - 1)) / rhs }
なお、対象は正数のみで、負数を考慮していません。(使う場面がなかったので・・・悪しからず)
(if
文にて場合分けするだけですが・・・)
↓ 使用例です。
var A = 10 /^ 3
//4
A /^= 3
//2
let B = 12 /^ 3
//4
let C = 13 /^ 3
//5
2. MOD演算子%%
Swift標準のMOD演算子%
と、負数の場合の結果が異なる(最小非負剰余の)%%
演算子を定義します。( Python の % に同じ)
(除数と符号が同じになる結果を返します)
infix operator %% : MultiplicationPrecedence // modulo
@inlinable func %%(lhs: Int, rhs: Int) -> Int { ((lhs % rhs) + rhs) % rhs }
次のように差が出ます。
print( 10 % 3) // 1
print( 10 %% 3) // 1
print( 10 % -3) // 1
print( 10 %% -3) // -2
print(-10 % 3) // -1
print(-10 %% 3) // 2
print(-10 % -3) // -1
print(-10 %% -3) // -1
3. 配列の末尾に追加する+=
演算子
array.append()
する演算子。タイプし易いので、使う頻度が高いです。
extension Array {
@inlinable static func += (lhs: inout Self, rhs: Self.Element) { lhs.append(rhs) }
}
一応、使用例を書いておきます。
var array = Array<Int>()
for a in 1...10 {
array += a
}
//array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
4. 集合を操作する いくつかの 演算子
これも使う頻度が高い方です。
内容は、実装を見てもらえば 一目瞭然だと思います。
extension Set {
@inlinable static func += (lhs: inout Self, rhs: Element) { lhs.insert(rhs) }
@inlinable static func -= (lhs: inout Self, rhs: Element) { lhs.remove(rhs) }
@inlinable static func += (lhs: inout Self, rhs: Self) { lhs.formUnion(rhs) }
@inlinable static func -= (lhs: inout Self, rhs: Self) { lhs.subtract(rhs) }
@inlinable static func + (lhs: Self, rhs: Self) -> Self { lhs.union(rhs) }
@inlinable static func - (lhs: Self, rhs: Self) -> Self { lhs.subtracting(rhs) }
}
var set = Set<Int>()
for a in 1...10 {
set += a
}
//set: [5, 6, 7, 9, 3, 4, 2, 10, 8, 1]
set -= Set(3...5)
//set: [9, 6, 7, 2, 10, 8, 1]
for s in set {
set -= s
}
// set: []
5. ”含む?” =~
演算子
5.1 範囲型 =~
演算子
infix operator =~ : ComparisonPrecedence
@inlinable func =~ <T: FixedWidthInteger>(lhs: T, rhs: Range<T>) -> Bool { rhs ~= lhs }
@inlinable func =~ <T: FixedWidthInteger>(lhs: T, rhs: ClosedRange<T>) -> Bool { rhs ~= lhs }
右側の範囲の中に含むか? を判定します。
if 0 <= x && x < 10
と等価ですが、変数x
を2回書かなくて済むメリットがあります。
( Python だと if 0 <= x < 10
と書けるのに近い?)
let x = 8
if x =~ 0 ..< 10 { } //then (true)
if x =~ 0 ... 7 { } //else (false)
もともとは if 0 ..< 10 ~= x { }
と書きます。
if case 0 ..< 10 = x { }
とも書けます。
関数を使って、if (0 ..< 10).contains(x) { }
とも書けます。
5.2 Sequence型 =~
演算子
範囲型 =~
演算子の流れで、今度は Collection に含むか? を判定します。
//infix operator =~ : ComparisonPrecedence
@inlinable func =~ <T: Collection> (lhs: T.Element, rhs: T) -> Bool where T.Element: Equatable { rhs.contains(lhs) }
主に集合型で使います。Arrayで使うと$O(N)$です!!
let set = Set([1, 3, 4, 6, 7, 9])
if 4 =~ set { } //then (true)
if 8 =~ set { } //else (false)
5.3 Dictionary型 =~
演算子
Sequence型 =~
演算子の流れで、今度は、Dictionary のkey
の存在チェックです。
しかし、これは推奨しません。理由は後述します。
extension Dictionary {
@inlinable func contains(key: Key) -> Bool { self.keys.contains(key) }
@inlinable static func =~ (lhs: Key, rhs: Self) -> Bool where Key: Hashable { rhs.contains(key: lhs) }
}
使い方
let dcit = ["A":0, "B":1, "C":2]
if "A" =~ dict { } //then (true)
if "D" =~ dict { } //else (false)
Dictionary型key
の存在チェック=~
演算子を推奨しない理由は、
Keyの存在チェックか、Valueの存在チェックか、=~
演算子を見ただけでは(知らない人には)判断できないからです。
よって、次の関数を使うことをオススめします。
let dcit = ["A":0, "B":1, "C":2]
if dict.contains(key: "A") { } //then (true)
if dict.contains(key: "D") { } //else (false)
引数ラベルのおかげで、曖昧性が排除できますね。
(作者の自分は”知っているので”、普通に=~
演算子を使います。タイプ数が”だんち”なので)
ちなみに、Dictionary のValue
の存在チェックは準備していません。$O(N)$のため使わないからです。
もし、Value
の存在チェックが必要なときは、Value
をkey
にした別なDictionary変数か、Value
を要素にしたSet変数を使い、こちらで存在チェックします。計算量が重要です。
6. 整数型floor演算子
↓ 以前に公開済みです
愚痴
本当は、”含む?” =~
演算子をin
にしたかったのですが、Swiftは、演算子に 英数字 を使うことができませ。残念!!