Swiftでお手軽ストップウォッチ実装

今回はシングルトンを使ったストップウォッチの実装を行いました。

現在私が作っているアプリがどうしてもスピード勝負になることが想定され、どのメソッドが一番処理に時間をかけているか調べる必要があったため、手軽に使えるように自分なりにコーディングしてみました。

#Code👨

```Swift
import Foundation

class StopWatch: NSObject {
    private static let measure: StopWatch = .init()
    private override init() {}
    
    var watches: [String : Date] = [:] 
    
    static func start(label: String) -> Void {
        let start: Date = Date()
        measure.watches.updateValue(start, forKey: label)
    }
    static func stop(label: String) -> Void {
        guard let start: Date = measure.watches[label] else { fatalError("Label doesn't exist.") }
        let time: TimeInterval = Date().timeIntervalSince(start)
        measure.watches.removeValue(forKey: label) 
        print(label, time)
    }
}
```


#Usage⚽️

結論としては、使い方はこのようになります。

```Swift
StopWatch.start(label: "アルファベットの冪集合を導出")
//冪集合を導出する（など、重い処理）
StopWatch.stop(label: "アルファベットの冪集合を導出")

// アルファベットの冪集合を導出: 67.86 seconds
// ↑このようにプリントされる
```


ちなみに[冪集合](https://ja.wikipedia.org/wiki/%E5%86%AA%E9%9B%86%E5%90%88)とは、ある集合の全ての部分集合を元にもつ集合で、例えば```{A, B}```の冪集合は```{Φ, {A}, {B}, {A, B}}```となります。

そして要素数が```N```の集合の冪集合は要素の数が ```2^N```となることが分かっており、
アルファベット全体のの冪集合の要素の数は```2^26 = 67,108,864```と膨大になります。


冪集合を計算する際の関数は再帰的に定義され、以下のように与えられます。
（参考：[Find all combination of string array in swift](https://stackoverflow.com/questions/41501930/array-contains-too-slow-swift/41509565)）

```Swift:Powerset（冪集合）
extension Array {
    var powerset: [[Element]] {
        guard count > 0 else {
            return [[]]
        }

        // tail contains the whole array BUT the first element
        let tail = Array(self[1..<endIndex])

        // head contains only the first element
        let head = self[0]

        // computing the tail's powerset
        let withoutHead = tail.powerset

        // mergin the head with the tail's powerset
        let withHead = withoutHead.map { $0 + [head] }

        // returning the tail's powerset and the just computed withHead array
        return withHead + withoutHead
    }
}
```


仕組みについては、今度[コンビネーション](https://ja.wikipedia.org/wiki/%E7%B5%84%E5%90%88%E3%81%9B_(%E6%95%B0%E5%AD%A6))の実装についても記事にしようと思っているのでその時に説明してみようと思います。

#Example🚗

上記で紹介した冪集合を使って、実際にPlaygroundで時間計測をしてみましょう。

### Let's measure the time

```Swift

// Uまで計測
let alphabet: [Character] = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U"]

// 総合計時間の計測
StopWatch.start(label: "Total time")

for i in 0..<alphabet.count {
    
    // i文字目までのアルファベットの冪集合の計算時間の計測
    StopWatch.start(label: "Alphabet's powerset elapse time \(i)")
    let powerset = Array(alphabet[0..<i]).powerset
    StopWatch.stop(label: "Alphabet's powerset elapse time \(i)")
    
    // カウント
    print("Alphabet's powerset count until \(alphabet[i])", powerset.count)
}

StopWatch.stop(label: "Total time")
```

###Result
```Swift:980秒(!)かかりました
Alphabet's powerset elapse time 0 0.005095005035400391
Alphabet's powerset count until A 1
Alphabet's powerset elapse time 1 0.0016039609909057617
Alphabet's powerset count until B 2
Alphabet's powerset elapse time 2 0.0014590024948120117
Alphabet's powerset count until C 4
Alphabet's powerset elapse time 3 0.002460002899169922
Alphabet's powerset count until D 8
Alphabet's powerset elapse time 4 0.008343935012817383
Alphabet's powerset count until E 16
Alphabet's powerset elapse time 5 0.012218952178955078
Alphabet's powerset count until F 32
Alphabet's powerset elapse time 6 0.24290001392364502
Alphabet's powerset count until G 64
Alphabet's powerset elapse time 7 0.48837602138519287
Alphabet's powerset count until H 128
Alphabet's powerset elapse time 8 0.39558398723602295
Alphabet's powerset count until I 256
Alphabet's powerset elapse time 9 0.35213494300842285
Alphabet's powerset count until J 512
Alphabet's powerset elapse time 10 0.6983180046081543
Alphabet's powerset count until K 1024
Alphabet's powerset elapse time 11 0.9306050539016724
Alphabet's powerset count until L 2048
Alphabet's powerset elapse time 12 1.2875239849090576
Alphabet's powerset count until M 4096
Alphabet's powerset elapse time 13 2.3467971086502075
Alphabet's powerset count until N 8192
Alphabet's powerset elapse time 14 5.930698037147522
Alphabet's powerset count until O 16384
Alphabet's powerset elapse time 15 11.123641014099121
Alphabet's powerset count until P 32768
Alphabet's powerset elapse time 16 23.158427953720093
Alphabet's powerset count until Q 65536
Alphabet's powerset elapse time 17 59.36393702030182
Alphabet's powerset count until R 131072
Alphabet's powerset elapse time 18 113.55426597595215
Alphabet's powerset count until S 262144
Alphabet's powerset elapse time 19 211.3655710220337
Alphabet's powerset count until T 524288
Alphabet's powerset elapse time 20 521.3869780302048
Alphabet's powerset count until U 1048576
Total time 980.5250370502472
```

なんと20文字目の U までで980秒もかかってしまいました。
このままZまでやったとしたらあと４時間かかる計算です。
Pythonだと恐らく一瞬でできるのですがいかにPlaygroundが重いかが分かると思います。
（ただ、Arrayの代わりにSetを利用するとか、Playground側の設定を変更するなどして速くすることはできます）


#Conclusion🥇
練習がてら記事を書いてみましたが、これからも何か書きやすいネタと時間があれば書いていこうと思います。
皆さんもぜひ使ってみてくださいねー👏



#宣伝

![スクリーンショット 2022-01-11 19.44.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540507/4de5d568-524f-e222-5a43-8a4116a55dfb.png)

「**[イラスト英語辞典](https://apps.apple.com/us/app/%E3%82%A4%E3%83%A9%E3%82%B9%E3%83%88%E8%8B%B1%E8%AA%9E%E8%BE%9E%E5%85%B8/id1604338862#?platform=iphone)**」は最新の心理学を応用した、誰でも簡単に英単語を記憶できるアプリです！

私は前に英検一級を目指していて、最初はその単語量の多さから苦悶していました。

しかし勉強法を試行錯誤してゆく中で、「**記憶するには、イラストを描くのが一番良い**」
というとあるカナダの大学の心理学の論文を読みました。

半信半疑になりつつも私は藁にすがる思いで試しに落書きしながら覚えてみたところ...


**これがめちゃくちゃ覚えやすいことが分かりました。**

![スクリーンショット 2022-02-23 3.16.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540507/754748fe-eab6-6d6d-26db-fc217b8292f7.png)



確かに、わざわざ単語ごとにイラストを描くのはコストがかかりますし、そもそも絵なんか描いて覚えられるのかよ！　と思うかも知れません。

ただ少なくともwatasiha、基本的には分からない単語というものがなくなり、文がスラスラ読めるようになりました。


そして何より、楽しく覚えられます！（それが一番のメリット！笑）




**無料なのでぜひインストールしてみてください！**🙌🙏

👉 **[AppleStore「イラスト英語辞典は神アプリ」](https://apps.apple.com/us/app/%E3%82%A4%E3%83%A9%E3%82%B9%E3%83%88%E8%8B%B1%E8%AA%9E%E8%BE%9E%E5%85%B8/id1604338862#?platform=iphone)**