ずんだの1桁足し算問題 Python編

[てぃーびーさん](https://qiita.com/tbpgr)の[ずんだの1桁足し算問題](https://qiita.com/tbpgr/items/6c75930566dda97bb5b6)を
Pythonで実装しました。

Pythonはfor文で書くと遅くなるのでやらない方が良いとの言説を見かけたものの、他の方法が思いつかず、最も愚直な方法で実装を試みました。

## 0. 先人たちの実装
* [ずんだの1桁足し算問題 PHP編](https://qiita.com/higuyume/items/83d53f18fd977c9f08d1)
* [ずんだの1桁足し算問題 JavaScript編](https://qiita.com/mascii/items/cf4521c7911e46391e05)
* [ずんだの1桁足し算問題 Kotlin 編](https://qiita.com/fumiya-kume/items/dbb154d361d17b6ef724)
* [ずんだの1桁足し算問題 Brainf**k版](https://qiita.com/angel_p_57/items/29fbb997d03c00b83b8b)
* [ずんだの1桁足し算問題 Java11編](https://qiita.com/neko_the_shadow/items/6320f9550c72fcd783eb)

## 1. 本文
### 私の実装
```
for i in  range(1,10):
    for j in range(1,10):
        total = i + j
        print(str(i)+"+"+str(j)+"="+"~"*total+str(i+j),sep="\n")
```

### 出力結果
```
1+1=~~2
1+2=~~~3
1+3=~~~~4
1+4=~~~~~5
1+5=~~~~~~6
1+6=~~~~~~~7
1+7=~~~~~~~~8
1+8=~~~~~~~~~9
1+9=~~~~~~~~~~10
2+1=~~~3
2+2=~~~~4
2+3=~~~~~5
2+4=~~~~~~6
2+5=~~~~~~~7
2+6=~~~~~~~~8
2+7=~~~~~~~~~9
2+8=~~~~~~~~~~10
2+9=~~~~~~~~~~~11
3+1=~~~~4
3+2=~~~~~5
3+3=~~~~~~6
3+4=~~~~~~~7
3+5=~~~~~~~~8
3+6=~~~~~~~~~9
3+7=~~~~~~~~~~10
3+8=~~~~~~~~~~~11
3+9=~~~~~~~~~~~~12
4+1=~~~~~5
4+2=~~~~~~6
4+3=~~~~~~~7
4+4=~~~~~~~~8
4+5=~~~~~~~~~9
4+6=~~~~~~~~~~10
4+7=~~~~~~~~~~~11
4+8=~~~~~~~~~~~~12
4+9=~~~~~~~~~~~~~13
5+1=~~~~~~6
5+2=~~~~~~~7
5+3=~~~~~~~~8
5+4=~~~~~~~~~9
5+5=~~~~~~~~~~10
5+6=~~~~~~~~~~~11
5+7=~~~~~~~~~~~~12
5+8=~~~~~~~~~~~~~13
5+9=~~~~~~~~~~~~~~14
6+1=~~~~~~~7
6+2=~~~~~~~~8
6+3=~~~~~~~~~9
6+4=~~~~~~~~~~10
6+5=~~~~~~~~~~~11
6+6=~~~~~~~~~~~~12
6+7=~~~~~~~~~~~~~13
6+8=~~~~~~~~~~~~~~14
6+9=~~~~~~~~~~~~~~~15
7+1=~~~~~~~~8
7+2=~~~~~~~~~9
7+3=~~~~~~~~~~10
7+4=~~~~~~~~~~~11
7+5=~~~~~~~~~~~~12
7+6=~~~~~~~~~~~~~13
7+7=~~~~~~~~~~~~~~14
7+8=~~~~~~~~~~~~~~~15
7+9=~~~~~~~~~~~~~~~~16
8+1=~~~~~~~~~9
8+2=~~~~~~~~~~10
8+3=~~~~~~~~~~~11
8+4=~~~~~~~~~~~~12
8+5=~~~~~~~~~~~~~13
8+6=~~~~~~~~~~~~~~14
8+7=~~~~~~~~~~~~~~~15
8+8=~~~~~~~~~~~~~~~~16
8+9=~~~~~~~~~~~~~~~~~17
9+1=~~~~~~~~~~10
9+2=~~~~~~~~~~~11
9+3=~~~~~~~~~~~~12
9+4=~~~~~~~~~~~~~13
9+5=~~~~~~~~~~~~~~14
9+6=~~~~~~~~~~~~~~~15
9+7=~~~~~~~~~~~~~~~~16
9+8=~~~~~~~~~~~~~~~~~17
9+9=~~~~~~~~~~~~~~~~~~18
```

## 2. 感想
* 他の言語版の記事を読み、自身の言語での実装を考えることでその言語の特徴を掴むことができるように感じた  
    * Pythonの文字列を\*(アスタリスク)で繰り返しする機能
    * sep=""で出力時の区切り文字を指定する機能
* 明らかな改善点
    * for文以外での実装方法がありそう
    * print文内部にstr()が複数回存在し記述が長くなるなどダサい

## 3. 追記 2018/10/08
コメント欄にてshiracamusさんに「ジェネレーター内包表記」を教えて頂きました。
私の愚直な実装に比べ、シンプルかつ高速に実行できるようです。
そのため以下のような実行時間を測定するコードを処理の前後に挿入し、私の実装と「ジェネレーター内包表記」の速度を計測・比較してみました。

```
import time
start_time = time.perf_counter()

# ここに1桁足し算問題の処理を記入

end_time = time.perf_counter()
elapsed_time = end_time - start_time
print(f'経過時間:{elapsed_time}sec')
```
### 計測結果
```
# 私の実装
import time
start_time = time.perf_counter()
for i in  range(1,10):
    for j in range(1,10):
        total = i + j
        print(str(i)+"+"+str(j)+"="+"~"*total+str(i+j),sep="\n")
end_time = time.perf_counter()
elapsed_time = end_time - start_time
print(f'経過時間:{elapsed_time}sec')

>>> 経過時間:0.0005901sec

# shiracamusさんの「ジェネレーター内包表記」
import time
start_time = time.perf_counter()
print("\n".join(f'{i}+{j}={"~"*(i+j)}{i+j}' for i in range(1, 10) for j in range(1, 10)))
end_time = time.perf_counter()
elapsed_time = end_time - start_time
print(f'経過時間:{elapsed_time}sec')

>>> 経過時間:0.0001559sec
```
結果、shiracamusさんの「ジェネレーター内包表記」の方が私の実装より**約3.8倍**高速であることが証明されました。
現状は短いコードであるため体感では気が付きませんでしたが、速さが求められるアプリ・システムでは通常の記法だけで実装するのは苦しいかもしれません。

### 今回の学び
* 「ジェネレーター内包表記」の書き方およびその処理の速さ
* Pythonにおける処理速度の計測方法

## 4. 追記における参照
* Pythonの内包表記について  
[pythonの内包表記を少し詳しく](https://qiita.com/y__sama/items/a2c458de97c4aa5a98e7)
* 処理時間の計測方法について  
[ミリ秒・マイクロ秒単位で処理時間を計測するには](https://hydrocul.github.io/wiki/programming_languages_diff/datetime/timer.html)
* 精度の高い処理時間の計測方法について  
[time.time()は精度があまりよくない？](https://qiita.com/takeopy/items/170d0e1ddbf02ef9fbb9)