1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Swift] あると便利(かも)な 演算子

Last updated at Posted at 2024-07-12

便利(かも)な 演算子 をいくつか紹介します

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の存在チェックが必要なときは、Valuekeyにした別なDictionary変数か、Valueを要素にしたSet変数を使い、こちらで存在チェックします。計算量が重要です。

6. 整数型floor演算子

↓ 以前に公開済みです

愚痴

本当は、”含む?” =~演算子をinにしたかったのですが、Swiftは、演算子に 英数字 を使うことができませ。残念!!

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?