『行列プログラマー』の課題・問題を解いてみる (0章 関数)


## はじめに

こちらの本を読みつつ、課題・問題を解いてみます。

- [O'Reilly Japan - 行列プログラマー](https://www.oreilly.co.jp/books/9784873117775/)

 ![](https://www.oreilly.co.jp/books/images/picture978-4-87311-777-5.gif)

まだ 0 章のみで、Python の勉強し直しな感じ。

**2017/01/04 更新**

「[0.6 ラボ：Python と逆インデックスーーーモジュールと制御構造](http://qiita.com/Suna/items/881ce264cffd3301a54f#06-ラボpython-と逆インデックスーーーモジュールと制御構造)」の課題を追記しました。

## 0章　関数（とその他の数学とコンピュータに関する予備知識）

### 0.5 ラボ：Python 入門−−−集合、リスト、辞書、内包表記

#### 0.5.1 簡単な式

##### 課題 0.5.1

> python を使用して、1週間が何秒かを求めよ。

```python
>>> 7 * 24 * 60 * 60
604800
```

##### 課題 0.5.2

> Python を使用して、2304811 を 47 で割った余りを求めよ。ただし、% を使用しないこと (ヒント：// を用いる)。

```python
>>> 2304811 - (2304811 // 47) * 47
25
```

##### 課題 0.5.3

> ブール式を入力して、673 と 909 の和が 3 で割り切れるかどうか調べよ。

```python
>>> (643 + 909) % 3 == 0
False
```

#### 0.5.2 代入文

#### 0.5.3 条件式

##### 課題 0.5.4

> -9 を x に、1/2 を y に代入する。以下の式の値を予想し、入力して予想を確認せよ。
> 2**(y+1/2) if x+10<0 else 2**(y-1/2)

x+10<0 が False になり、else 部分 2**(y-1/2) が実行されるため、「1」になる。

```python
>>> (lambda x, y: 2**(y+1/2) if x+10<0 else 2**(y-1/2))(-9, 1/2)
1
```

#### 0.5.4 集合

##### 課題 0.5.5

> 集合 {1, 2, 3, 4, 5} に対する内包表記で、それぞれの整数の 2 乗を返すものを書け。

```python
>>> {x * x for x in {1, 2, 3, 4, 5}}
set([16, 1, 4, 25, 9])
```

##### 課題 0.5.6

> 集合 {0, 1, 2, 3, 4} に対する内包表記で、それぞれの整数を 2 の指数に持つ値、即ち、2<sup>0</sup>、2<sup>1</sup>、2<sup>2</sup> などを返すものを書け。

```python
>>> {2**x for x in {0, 1, 2, 3, 4}}
set([8, 1, 2, 4, 16])
```

##### 課題 0.5.7

> 前の内包表記 {x*y for x in {1, 2, 3} for y in {2, 3, 4}} の値は、7 つの要素からなる集合である。
> {1, 2, 3} と {2, 3, 4} をそれぞれ別の 3 つの要素の集合で置き換え、その値が 9 つの要素の集合となるようにせよ。

```python
>>> {x * y for x in {4, 5, 6} for y in {6, 7, 8}}
set([32, 35, 36, 40, 42, 48, 24, 28, 30])
```

##### 課題 0.5.8

> 前の内包表記内の 2 つの集合 {1, 2, 3} と {2, 3, 4} をそれぞれ別の 3 つの要素の集合で置き換え、結果が 5 つの要素の集合とあるようにせよ。ただし、置き換える 2 つの集合は互いに素、つまり要素が重複していないこととする。

```python
>>> {x * y for x in {4, 5, 6} for y in {7, 8, 9} if x * y < 41}
set([32, 28, 35, 36, 40])
```

##### 課題 0.5.9

> 変数 S、T は集合を表すものとする。演算子 & を用いずに S と T の共通部分を返すような S に対する内包表記を書け (ヒント：内包表記の最後にフィルタを用い、要素をチェックせよ)。
> 作成した内包表記を S = {1, 2, 3, 4} と T = {3, 4, 5, 6} で試せ。

```python
>>> {s for s in {1, 2, 3, 4} for t in {3, 4, 5, 6} if s == t}
set([3, 4])
```

#### 0.5.5 リスト

##### 課題 0.5.10

> 評価した値がリスト [20, 10, 15, 75] の要素の平均となる式を書け。

```python
>>> sum([20, 10, 15, 75]) / 4
30
```

##### 課題 0.5.11

> リスト ['A', 'B', 'C'] 及び [1, 2, 3] に対するリスト内包表記で、その値が [文字, 数字] の全ての可能な組み合わせから成るものを書け。即ち、その値は以下のようなものである。
> [['A', 1], ['A', 2], ['A', 3], ['B', 1], ['B', 2], ['B', 3], ['C', 1], ['C', 2], ['C', 3]]

```python
>>> [[a, b] for a in ['A', 'B', 'C'] for b in [1, 2, 3]]
[['A', 1], ['A', 2], ['A', 3], ['B', 1], ['B', 2], ['B', 3], ['C', 1], ['C', 2], ['C', 3]]
```

##### 課題 0.5.12

> LofL に数字のリストを要素に持つリストを代入したとしよう。このとき、そのリスト全ての数値全部を足した合計を計算する式を書け。この式は次の形を持ち、内包表記を 1 つ持つ。
> sum([sum(...
> [[0.25, 0.75, 0.1], [-1, 0], [4, 4, 4, 4]] を LofL に代入し、作成した式を試せ (注意：作成した式はどのような長さのリストでも動くようにすること)。

```python
>>> sum([sum(x) for x in [[0.25, 0.75, 0.1], [-1, 0], [4, 4, 4, 4]]])
16.1
```

##### 課題 0.5.13

> 左辺のリストの長さが右辺のリストの長さと一致しない場合、何が起こるか確認せよ。

```python
>>> [x, y, z] = [4*1, 4*2, 4*3, 4*4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ValueError: too many values to unpack
```

#### 0.5.6 タプル

##### 課題 0.5.14

> S をある整数の集合、例えば {-4, -2, 1, 2, 5, 0} とする。評価すると、次の条件を満たす 3 要素タプル (i, j, k) から成るリストとなる、3 重の内包表記を書け。ここで、i, j, k は S の要素で、その合計は 0 であるとする。

```python
>>> S = {-4, -2, 1, 2, 5, 0}
>>> [(i, j, k) for i in S for j in S for k in S if i+j+k == 0]
[(0, 0, 0), (0, 2, -2), (0, -2, 2), (1, 1, -2), (1, -2, 1), (2, 0, -2), (2, 2, -4), (2, -4, 2), (2, -2, 0), (-4, 2, 2), (-2, 0, 2), (-2, 1, 1), (-2, 2, 0)]
```

##### 課題 0.5.15

> 前の問題の内包表記を変更し、結果のリストに (0, 0, 0) が含まれないようにせよ (ヒント：フィルタを追加せよ)。

```python
>>> [(i, j, k) for i in S for j in S for k in S if i+j+k == 0 and (i != 0 or j != 0 or k != 0)]
[(0, 2, -2), (0, -2, 2), (1, 1, -2), (1, -2, 1), (2, 0, -2), (2, 2, -4), (2, -4, 2), (2, -2, 0), (-4, 2, 2), (-2, 0, 2), (-2, 1, 1), (-2, 2, 0)]
```

##### 課題 0.5.16

> 更にその式を変更し、式の値が、上記のタプル全部から成るリストではなく、最初のタプルとなるようにせよ。

```python
>>> [(i, j, k) for i in S for j in S for k in S if i+j+k == 0 and (i != 0 or j != 0 or k != 0)][0]
(0, 2, -2)
```

##### 課題 0.5.17

> len(L) と len(list(set(L))) が異なるリスト L の例を見つけよ。

```python
>>> L = [1, 1, 2, 3]
>>> len(L)
4
>>> len(list(set(L)))
3
```

#### 0.5.7 その他の繰り返し処理について

##### 課題 0.5.18

> range(n) の形をした範囲に対し、1〜99 の間の奇数の集合を返す内包表記を書け。

```python
>>> {x for x in range(100) if x % 2 == 1}
set([1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99])
```

##### 課題 0.5.19

> L にアルファベットの最初の 5 文字 ['A', 'B', 'C', 'D', 'E'] から成るリストを代入せよ。L を用いて次のリストを値とする式を書け。
> [(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D'), (4, 'E')]
> range と zip は用いてよいが、内包表記を用いてはならない。

```python
>>> L = ['A', 'B', 'C', 'D', 'E']
>>> zip(range(len(L)), L)
[(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D'), (4, 'E')]
```

##### 課題 0.5.20

> リスト [10, 25, 40] と [1, 15, 20] に対し、1 番目の要素が 10 と 1 の合計、2番目の要素が 25 と 15 の合計、3 番目の要素が 40 と 20 の合計となるようなリストを値とする内包表記を書け。zip は用いてもよいが、list を用いてはならない。

```python
>>> [sum(a) for a in zip([10, 25, 40], [1, 15, 20])]
[11, 40, 60]
```

#### 0.5.8 辞書

##### 課題 0.5.21

> dlist を辞書のリスト、k を dlist の全ての辞書が共通に持つキーとする。i 番目の要素が dlist の i 番目の辞書のキー k に対応する値となるようなリストの内包表記を書け。
> 作成した内包表記をいくつかのデータで試せ。以下に例となるデータを示す。
>
> dlist = [{'James':'Sean', 'director':'Terence'}, {'James':'Roger', 'director':'Lewis'}, {'James':'Pierce', 'director':'Roger'}]
> k = 'James'

```python
>>> dlist = [{'James':'Sean', 'director':'Terence'}, {'James':'Roger', 'director':'Lewis'}, {'James':'Pierce', 'director':'Roger'}]
>>> k = 'James'
>>> [d[k] for d in dlist]
['Sean', 'Roger', 'Pierce']
```

##### 課題 0.5.22

> 課題 0.5.21 の内包表記を変更し、k をキーに持たない辞書がある場合も処理できるようにせよ。この内包表記によるリストの i 番目の要素は、dlist 内の i 番目の辞書にキー k が含まれている場合はそのキーに対応する値で、キーが含まれていない場合は 'NOT PRESENT' とする
> 作成した内包表記を、k = 'Blibo' と k = 'Frodo' のそれぞれについて、以下の辞書のリストを用いてテストせよ。
>
> dlist = [{'Blibo':'Ian', 'Frodo':'Elijah'}, {'Blibo':'Martin', 'Thorin':'Richard'}]

```python
>>> dlist = [{'Blibo':'Ian', 'Frodo':'Elijah'}, {'Blibo':'Martin', 'Thorin':'Richard'}]
>>> k = 'Blibo'
>>> [d[k] if k in d else 'NOT PRESENT' for d in dlist]
['Ian', 'Martin']
>>> k = 'Frodo'
>>> [d[k] if k in d else 'NOT PRESENT' for d in dlist]
['Elijah', 'NOT PRESENT']
```

##### 課題 0.5.23

> range を用いて、評価すると、キーが 0〜99 の整数で、キーの値がキーの 2 乗となる辞書となる内包表記を書け。

```python
>>> {x:x*x for x in range(100)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81, 10: 100, 11: 121, 12: 144, 13: 169, 14: 196, 15: 225, 16: 256, 17: 289, 18: 324, 19: 361, 20: 400, 21: 441, 22: 484, 23: 529, 24: 576, 25: 625, 26: 676, 27: 729, 28: 784, 29: 841, 30: 900, 31: 961, 32: 1024, 33: 1089, 34: 1156, 35: 1225, 36: 1296, 37: 1369, 38: 1444, 39: 1521, 40: 1600, 41: 1681, 42: 1764, 43: 1849, 44: 1936, 45: 2025, 46: 2116, 47: 2209, 48: 2304, 49: 2401, 50: 2500, 51: 2601, 52: 2704, 53: 2809, 54: 2916, 55: 3025, 56: 3136, 57: 3249, 58: 3364, 59: 3481, 60: 3600, 61: 3721, 62: 3844, 63: 3969, 64: 4096, 65: 4225, 66: 4356, 67: 4489, 68: 4624, 69: 4761, 70: 4900, 71: 5041, 72: 5184, 73: 5329, 74: 5476, 75: 5625, 76: 5776, 77: 5929, 78: 6084, 79: 6241, 80: 6400, 81: 6561, 82: 6724, 83: 6889, 84: 7056, 85: 7225, 86: 7396, 87: 7569, 88: 7744, 89: 7921, 90: 8100, 91: 8281, 92: 8464, 93: 8649, 94: 8836, 95: 9025, 96: 9216, 97: 9409, 98: 9604, 99: 9801}
```

##### 課題 0.5.24

> 適当な集合を変数 D に代入せよ。例えば、D = {'red', 'white', 'blue'} などだ。評価すると D に対する恒等関数を表す辞書となる内包表記を書け。

```python
>>> D = {'red', 'white', 'blue'}
>>> {x:x for x in D}
{'blue': 'blue', 'white': 'white', 'red': 'red'}
```

- これで良いのかな？
 
##### 課題 0.5.25

> base = 10 と digits = set(range(base)) という変数を用いて、0〜999 のそれぞれの整数を、底を 10 とした時のそれぞれの位を表す 3 つの数字のリストに写像する辞書内包表記を書け。
>
> {0: [0, 0, 0], 1: [0, 0, 1], 2: [0, 0, 2], 3: [0, 0, 3], ...
> 10: [0, 1, 0], 11: [0, 1, 1], 12: [0, 1, 2], ...
> 999: [9, 9, 9]}
>
> なお、作成した式が、どのような底についても動くようにすること。例えば、2 を base に、{0, 1} を digits に代入した場合、あたいは以下のようになる。
>
> {0: [0, 0, 0], 1: [0, 0, 1], 2: [0, 1, 0], ..., 7: [1, 1, 1]}

```python
>>> base = 10
>>> digits = set(range(base))
>>> {x:[x/(base**2)%base, x/(base**1)%base, x/(base**0)%base] for x in range(110)}
{0: [0, 0, 0], 1: [0, 0, 1], 2: [0, 0, 2], 3: [0, 0, 3], 4: [0, 0, 4], 5: [0, 0, 5], 6: [0, 0, 6], 7: [0, 0, 7], 8: [0, 0, 8], 9: [0, 0, 9], 10: [0, 1, 0], 11: [0, 1, 1], 12: [0, 1, 2], 13: [0, 1, 3], 14: [0, 1, 4], 15: [0, 1, 5], 16: [0, 1, 6], 17: [0, 1, 7], 18: [0, 1, 8], 19: [0, 1, 9], 20: [0, 2, 0], 21: [0, 2, 1], 22: [0, 2, 2], 23: [0, 2, 3], 24: [0, 2, 4], 25: [0, 2, 5], 26: [0, 2, 6], 27: [0, 2, 7], 28: [0, 2, 8], 29: [0, 2, 9], 30: [0, 3, 0], 31: [0, 3, 1], 32: [0, 3, 2], 33: [0, 3, 3], 34: [0, 3, 4], 35: [0, 3, 5], 36: [0, 3, 6], 37: [0, 3, 7], 38: [0, 3, 8], 39: [0, 3, 9], 40: [0, 4, 0], 41: [0, 4, 1], 42: [0, 4, 2], 43: [0, 4, 3], 44: [0, 4, 4], 45: [0, 4, 5], 46: [0, 4, 6], 47: [0, 4, 7], 48: [0, 4, 8], 49: [0, 4, 9], 50: [0, 5, 0], 51: [0, 5, 1], 52: [0, 5, 2], 53: [0, 5, 3], 54: [0, 5, 4], 55: [0, 5, 5], 56: [0, 5, 6], 57: [0, 5, 7], 58: [0, 5, 8], 59: [0, 5, 9], 60: [0, 6, 0], 61: [0, 6, 1], 62: [0, 6, 2], 63: [0, 6, 3], 64: [0, 6, 4], 65: [0, 6, 5], 66: [0, 6, 6], 67: [0, 6, 7], 68: [0, 6, 8], 69: [0, 6, 9], 70: [0, 7, 0], 71: [0, 7, 1], 72: [0, 7, 2], 73: [0, 7, 3], 74: [0, 7, 4], 75: [0, 7, 5], 76: [0, 7, 6], 77: [0, 7, 7], 78: [0, 7, 8], 79: [0, 7, 9], 80: [0, 8, 0], 81: [0, 8, 1], 82: [0, 8, 2], 83: [0, 8, 3], 84: [0, 8, 4], 85: [0, 8, 5], 86: [0, 8, 6], 87: [0, 8, 7], 88: [0, 8, 8], 89: [0, 8, 9], 90: [0, 9, 0], 91: [0, 9, 1], 92: [0, 9, 2], 93: [0, 9, 3], 94: [0, 9, 4], 95: [0, 9, 5], 96: [0, 9, 6], 97: [0, 9, 7], 98: [0, 9, 8], 99: [0, 9, 9], 100: [1, 0, 0], 101: [1, 0, 1], 102: [1, 0, 2], 103: [1, 0, 3], 104: [1, 0, 4], 105: [1, 0, 5], 106: [1, 0, 6], 107: [1, 0, 7], 108: [1, 0, 8], 109: [1, 0, 9]}

>>> base = 2
>>> {x:[x/(base**2)%base, x/(base**1)%base, x/(base**0)%base] for x in range(8)}
{0: [0, 0, 0], 1: [0, 0, 1], 2: [0, 1, 0], 3: [0, 1, 1], 4: [1, 0, 0], 5: [1, 0, 1], 6: [1, 1, 0], 7: [1, 1, 1]}
```

- 999 までだと長いので 取り急ぎ 109 まで。
- digits を使っていない。

##### 課題 0.5.26

> d を従業員番号 (0〜n-1 の間の整数) を給料に写像する辞書とする。L が n 個の要素のリストであり、その i 番目の要素が従業員番号 i の従業員の名前であるとする。従業員の名前を給料に写像する辞書の内包表記を書け。従業員の名前は異なる仮定としてよい。
> 作成した内包表記を以下のデータでテストせよ。
>
> d = {0:1000.0, 3:990, 1:1200.50}
> L = ['Larry', 'Curly', '', 'Moe']

```python
>>> d = {0:1000.0, 3:990, 1:1200.50}
>>> L = ['Larry', 'Curly', '', 'Moe']
>>> {L[k]:d[k] for k in d.keys()}
{'Larry': 1000.0, 'Moe': 990, 'Curly': 1200.5}
```

#### 0.5.9 1 行プロシージャを定義する

##### 課題 0.5.27

> twice(z) の定義を入力せよ。入力後、「...」が表示されるので、Enter を押す。次にいくつかの実引数でプロシージャを呼び出してみよ。文字列やリストで試しても面白いだろう。最後に変数 z から成る式を評価し、z がどのような値にもバインドされていないことを確かめよ。

```python
>>> def twice(z): return 2*z
...
>>> twice(2)
4
>>> twice(4)
8
>>> z
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  NameError: name 'z' is not defined
```

##### 課題 0.5.28

> 以下のような 1 行プロシージャ nextInts(L) を定義せよ。
>
> 入力：整数のリスト L
> 出力：i 番目の要素が L の i 番目の要素よりも　1 大きい整数のリスト
> 例：入力 [1, 5, 7]、出力：[2, 6, 8]

```python
>>> def nextInts(L): return [x+1 for x in L]
...
>>> nextInts([1, 5, 7])
[2, 6, 8]
```

##### 課題 0.5.29

> 以下のような 1 行プロシージャ cubes(L) を定義せよ。
>
> 入力：数のリスト L
> 出力：i 番目の要素が L の i 番目の要素の 3 乗になっている数のリスト
> 例：入力 [1, 2, 3]、出力 [1, 8 27]

```python
>>> def cubes(L): return [pow(x, 3) for x in L]
...
>>> cubes([1, 2, 3])
[1, 8, 27]
```

##### 課題 0.5.30

> 以下のような 1 行プロシージャ dict2list(dct, keylist) を定義せよ。
>
> 入力：辞書 dct、dct のキーから成るリスト keylist
> 出力：i = 0, 1, 2, ..., len(keylist)-1 に対して L[i] = dct[keylist[i]] と成るようなリスト L
> 例：入力 dct = {'a': 'A', 'b': 'B', 'c': 'C'} と keylist = ['b', 'c', 'a']、出力 ['B', 'C', 'A']

```python
>>> def dict2list(dct, keylist): return [dct[k] for k in keylist]
...
>>> dict2list({'a':'A', 'b':'B', 'c':'C'}, ['b', 'c', 'a'])
['B', 'C', 'A']
```

##### 課題 0.5.31

> 以下のような 1 行プロシージャ list2dict(L, keylist) を定義せよ。
>
> 入力：リスト L、変更不可能な要素から成るリスト keylist
> 出力：i = 0, 1, 2, ..., len(L)-1 に対して、keylist[i] を L[i] に写像する辞書
> 例：入力 L = ['A', 'B', 'C'] と keylist = ['a', 'b', 'c']、出力 {'a':'A', 'b':'B', 'c':'C'}

```python
>>> def list2dict(L, keylist): return {keylist[k]:L[k] for k in range(len(keylist))}
...
>>> list2dict(['A', 'B', 'C'], ['a', 'b', 'c'])
{'a': 'A', 'c': 'C', 'b': 'B'}
```

##### 課題 0.5.32

> 以下のプロシージャ all_3_digit_numbers(base, digits) を書け。
>
> 入力：正の整数 base と、{0, 1, 2, ..., base-1} である集合 digits
> 出力：底が base である 3 つの数字全てからなる数の集合
> 例を以下に示す。
>
> &gt;&gt;&gt; all_3_digit_number(2, {0, 1})
> {0, 1, 2, 3, 4, 5, 6, 7}
> &gt;&gt;&gt; all_3_digit_number(3, {0, 1, 2})
> {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26}
> &gt;&gt;&gt; all_3_digit_number(10, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
> {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ..., 995, 996, 997, 998, 999}

```python
>>> def all_3_digit_number(base, digits): return {a*pow(base, 2) + b*pow(base, 1) + c*pow(base, 0) for a in digits for b in digits for c in digits}
...
>>> all_3_digit_number(2, {0, 1})
set([0, 1, 2, 3, 4, 5, 6, 7])
>>> all_3_digit_number(3, {0, 1, 2})
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26])
>>> all_3_digit_number(10, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, (略)..., 995, 996, 997, 998, 999])
```


---

### 0.6 ラボ：Python と逆インデックスーーーモジュールと制御構造

#### 0.6.1 既存モジュールの利用

##### 課題 0.6.1

> 次のコマンドを用いて math をインポートせよ。
>
> &gt;&gt;&gt; import math
>
> インポートしたモジュールに対し、プロシージャ help(モジュール名) を使ってみよ。
>
> &gt;&gt;&gt; help(math)
>
> この結果、指定したモジュールのドキュメントがコンソールに表示される。f で下に進み、b で上に戻ることができる。また、q ドキュメントの閲覧を終了できる。
> math モジュールで定義されているプロシージャを用いて 3 の平方根を求め、更にその 2 乗を求めよ。この結果は思った通りにはならないだろう。Python は整数以外の実数の精度は限られているということを覚えておいて欲しい。そのため、答えは近似値になるのである。
> 次に、-1 の平方根、π に対する cos、<i>e</i> に対する自然対数を計算してみよ。
> 平方根を計算する関数の名前は sqrt であり、修飾名は math.sqrt である。cos と log はそのままの名前である。また、π と <i>e</i> の名前は pi と e である。

```python
>>> import math

>>> math.sqrt(3)
1.7320508075688772

>>> pow(math.sqrt(3), 2)
2.9999999999999996

>>> math.sqrt(-1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: math domain error

>>> math.cos(math.pi)
-1.0

>>> math.log(math.e)
1.0
```

- help は略。

##### 課題 0.6.2

> random モジュールは、プロシージャ randint(a, b) を定義している。これは {a, a+1, ..., b} の間の整数を無作為に選んで返す関数である。このプロシージャは次のコマンドでインポートできる。
>
> &gt;&gt;&gt; from random import randint
>
> randint を何回か実行してみよ。その後、映画の名前を引数に取り、レビューの文字列を返す 1 行プロシージャ movie_review(name) を書け。ただし、レビューの文字列は 2 つ以上の候補から無作為に選択すること (レビューの文字列は、"See it!" (見るべし)、"A gem!" (素晴らしい！)、"Ideological claptrap!" (イデオロギー的なウケ狙い！) などとせよ)。

```python
>>> from random import randint
>>> randint(0, 9)
3
>>> randint(0, 9)
1
>>> randint(0, 9)
9

>>> def movie_review(name): return ['See it!', 'A gem!', 'Ideological claptrap!'][randint(0, 2)]
...
>>> movie_review('movie_name')
'See it!'
>>> movie_review('movie_name')
'A gem!'
>>> movie_review('movie_name')
'Ideological claptrap!'
>>> movie_review('movie_name')
'A gem!'
>>> movie_review('movie_name')
'A gem!'
```

#### 0.6.2 モジュールの作成

##### 課題 0.6.3

> ラボ 0.5 の課題 0.5.30 と 0.5.31 では、dict2list(dct, keylist) と list2dict(L, keylist) というプロシージャを書いた。dictutil.py を本書のウェブサイトからダウンロードし、ファイル内で pass となっている部分を適切な文に置き換えよ。このモジュールをインポートし、プロシージャをそれぞれテストせよ。このモジュールはこの先使用する。

```python:dictutil.py
def dict2list(dct, keylist): return [dct[k] for k in keylist]

def list2dict(L, keylist): return {keylist[k]:L[k] for k in range(len(keylist))}
```

```python
>>> import dictutil
>>> dictutil.dict2list({'a':'A', 'b':'B', 'c':'C'}, ['b', 'c', 'a'])
['B', 'C', 'A']
>>> dictutil.list2dict(['A', 'B', 'C'], ['a', 'b', 'c'])
{'a': 'A', 'c': 'C', 'b': 'B'}
```

##### 課題 0.6.4

> dictutil.py を修正し、以下の機能を持つプロシージャ listrange2dict(L) を定義せよ。
>
> 入力：リスト L
> 出力：i = 0, 1, 2, ..., len(L)-1 に対して i を L[i] に写像する辞書
>
> このプロシージャは一から書くか、list2dict(L, keylist) を使って書くことができる。次の文を使うとモジュールを再読み込みできる。
>
> &gt;&gt;&gt; reload(dictutil)
>
> 読み込めたら、listrange2dict を ['A', 'B', 'C'] でテストせよ。

```python:dictutil.py
...
def listrange2dict(L): return {i:L[i] for i in range(len(L))}
```

```python
>>> reload(dictutil)
<module 'dictutil' from 'dictutil.py'>
>>> dictutil.listrange2dict(['A', 'B', 'C'])
{0: 'A', 1: 'B', 2: 'C'}
```

#### 0.6.3 ループと条件文

#### 0.6.4 字下げによる Python のグループ化機能

##### 課題 0.6.5

> 上記の for ループを Python に入力せよ。最初の行を入力すると Python は省略記号「...」を表示する。これは、字下げされたブロックが来ることを期待するものだ。次の行は、最初にスペースを 1 つか 2 つ入れてから入力せよ。Python は再び省略記号を表示する。1 つか 2 つ (前の行と同じ個数) スペースを入力し、次の行を入力する。今度も Python は省略記号を表示する。Enter を押すと、ループを実行する。

```python
>>> for x in [1, 2, 3]:
...   y = x * x
...   print(y)
...
1
4
9
```

#### 0.6.5 ループからの脱出

#### 0.6.6 ファイルからの読み込み

#### 0.6.7 ミニ検索エンジン

##### 課題 0.6.6

> 文字列 (文書) が与えられると、単語をその単語が現れる文書の文書番号から成る集合に写像する辞書を返すプロシージャ makeInverseIndex(strlist) を書け。この辞書を逆インデックスと呼ぶ (ヒント：enumerate を用いよ)。

```python:inverseindex.py
def makeInverseIndex(strlist):
  worddict = {}
  for no, line in enumerate(strlist):
    for word in list(set(line.split())):
      if word in worddict:
        worddict[word].add(no)
      else:
        worddict[word] = {no}
  return worddict
```

```python
>>> import inverseindex
>>> f = open('stories_small.txt')
>>> stories = list(f)

>>> dict = inverseindex.makeInverseIndex(stories)

>>> dict['prep']
set([0, 17])
>>> dict['course']
set([0, 2, 3, 4, 5, 49, 9, 10, 13, 47, 17, 18, 20])
```

##### 課題 0.6.7

> 逆インデックス inverseIndex と単語のリスト query を受け取り、query 内の単語のどれかが含まれている文書の文書番号の集合を返すプロシージャ orSearch(inverseIndex, query) を作成せよ。

```python:inverseindex.py
...

def orSearch(inverseIndex, query):
  result = set([])
  for k, v in inverseIndex.items():
    for q in query:
      if k == q:
		result = result | v
  return result
```

- 実行

```python
>>> inverseindex.orSearch(dict, ['prep', 'course'])
set([0, 2, 3, 4, 5, 49, 9, 10, 13, 47, 17, 18, 20])
```

- 確認

```bash
$ egrep -n -e ' prep ' stories_small.txt | cut -c -80
1:A prep course for the month-long World Cup soccer tournament , a worldwide phe
18:A prep course for the month-long World Cup soccer tournament , a worldwide ph

$ egrep -n -e ' course ' stories_small.txt | cut -c -80
1:A prep course for the month-long World Cup soccer tournament , a worldwide phe
3:Are frequent-flier awards worth all the trouble travelers sometimes go through
4:The State Department is taking a wait-and-see attitude after an American touri
5:I think there are several reasons why , in polite company , we rarely talk abo
6:By conventional wisdom , there are certain things you simply don't do , right
10:Llamas will carry the load on a three-day guided hiking and camping trip in t
11:Considering that the United Nations has recently created a Bosnian war-crimes
14:When I first got off the Pennsylvania Turnpike at Morgantown , I barely glanc
18:A prep course for the month-long World Cup soccer tournament , a worldwide ph
19:It is only natural that a writer make the literary most of whatever happens t
21:Step by step , President Clinton seems to be maneuvering himself into a posit
48:HOLLYWOOD When the editor of Tricycle , the Buddhist Review , one of the few
50:Eddie Murphy has been telling interviewers , in no uncertain terms , that ``
```

##### 課題 0.6.8

> 逆インデックス inverseIndex と単語のリスト query を受け取り、query 内の単語の全てが含まれている文書の文書番号の集合を返すプロシージャ andSearch(inverseIndex, query) を書け。

```python:inverseindex.py
...

def andSearch(inverseIndex, query):
  result = set([])
  for k, v in inverseIndex.items():
    for q in query:
      if k == q:
        if len(result) == 0:
          result = result | v
        else:
          result = result & v
  return result
```

- 実行

```python
>>> inverseindex.andSearch(dict, ['prep', 'course'])
set([0, 17])
```

- 確認

```bash
$ egrep -n -e ' prep ' stories_small.txt | egrep -e ' course ' | cut -c -80
1:A prep course for the month-long World Cup soccer tournament , a worldwide phe
18:A prep course for the month-long World Cup soccer tournament , a worldwide ph
```