Data Structures

昨日の続きです。

Tuples and Sequences

ここではTupleというデータ構造について勉強します。なおSequenceとはstr, unicode, list, tuple, bytearray, buffer, xrangeといった一連のオブジェクトをひとまとめ (Packing) したものの総称です。

>>> t = 12345, 54321, 'hello!'
>>> t[0]
12345
>>> t
(12345, 54321, 'hello!')
>>> u = t, (1, 2, 3, 4, 5)
>>> u
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))


Tupleの出力結果を見るとどれも括弧で囲まれていますが、入力時は括弧を省くことが出来ます。でも分かりやすさからいって括弧はつけた方がいいんでしょうね。なお、Tupleは文字列と同様に一旦定義すると変更出来ません (immutable) 。もちろん変更可能な (mutable) オブジェクトをTupleの要素にすることは可能です。また注意しないといけないのは要素が一つのTupleです。書き方にちょっと癖 (quirk) があります。

>>> singleton = 'Hello!',    # カンマを付けるとTupleと認識される
>>> len(singleton)
1
>>> singleton
('Hello!',)
>>> singleton = 'hello!'     # カンマを付けないと文字列と認識される
>>> singleton
'hello!'
>>> len(singleton)
6


実は要素が一つのTupleは絶対にカンマを付けないといけないのです。括弧を付けてもダメです。

>>> singleton = ('Hello?')    # カンマがないから括弧を付けても文字列
>>> singleton
'Hello?'
>>> len(singleton)
6


最後にちょっと面白い構文です。Sequenceデータ構造はどれもTupleに展開 (Unpacking) することが出来ます。

>>> x, y, z = (12345, 54321, 'hello!')
>>> x
12345
>>> y
54321
>>> z
'hello!'
>>> a, b, c, d, e = [1, 2, 3, 4, 5]
>>> a
1
>>> b
2
>>> c
3
>>> d
4
>>> e
5


右辺の変数の数は左辺のSequenceの要素数に等しくないといけないので少し使いにくいかな。

Sets

Setというデータ構造は要素に重複を許さない、順番が維持されないSequenceです。主な使い道はデータの有無をチェックすることでしょう。

>>> basket = ['apple', 'orange', 'apple' 'pear', 'orange', 'banana']
>>> furuit = set(basket)
>>> fruit = set(basket)
>>> fruit
set(['orange', 'applepear', 'apple', 'banana'])
>>> 'orange' in fruit        # ruitの中に'orange'は含まれるか?
True
>>> 'crabgrass' in fruit     # fruitの中に'crabgrass'は含まれるか?
False


また基本的な集合演算も可能です。

>>> a = set('abcracadabra')
>>> b = set('alacazam')
>>> a
set(['a', 'c', 'b', 'r', 'd'])
>>> b
set(['a', 'c', 'z', 'm', 'l'])
>>> a - b    # aとbの差集合
set(['r', 'b', 'd'])
>>> a | b    # aとbの和集合
set(['a', 'c', 'b', 'd', 'm', 'l', 'r', 'z'])
>>> a & b    # aとbの積集合
set(['a', 'c'])
>>> a ^ b    # aとbの対象差 (排他的論理和)
set(['b', 'd', 'm', 'l', 'r', 'z'])


ちなみにSetはSequenceではありません。なので添字で要素にアクセスすることは出来ません。

>>> a[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'set' object does not support indexing

Dictionaries

こちらもSetと同様にSequenceではありません。添字でアクセス出来るSequenceと違い、DictionaryはKeyで要素にアクセスします。ここで注意が必要なのはKeyには変更不可 (immutable) でないといけません。文字列だったり数値だったり。リストなどはappend出来たりするのでNGです。

>>> tel = {'jack':4098, 'sape':4139}
>>> tel['guido'] = 4127    # 要素の追加
>>> tel
{'sape': 4139, 'jack': 4098, 'guido': 4127}
>>> tel['jack']            # 要素の参照
4098
>>> del tel['sape']        # 要素の削除
>>> tel
{'jack': 4098, 'guido': 4127}
>>> tel.keys()             # DictionaryのKeyを抽出
['jack', 'guido']
>>> 'guido' in tel         # Keyの存在確認
True


またdict()という関数 (コンストラクタ) を使うとTupleのリストからDictionaryを生成することが出来ます。もちろんリスト内表現もOKです。

>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'jack': 4098, 'guido': 4127}
>>> dict([(x, x ** 2) for x in [2, 4, 6]])
{2: 4, 4: 16, 6: 36}


こんな書き方も出来ます。

>>> dict(sape=4139, jack=4098, guido=4127)
{'sape': 4139, 'jack': 4098, 'guido': 4127}


こっちの方が感覚的かな。

Looping Techniques

Dictionaryをループで回す時便利な関数があります。

>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.iteritems():
...     print k, v
... 
gallahad the pure
robin the brave


iteritems() (Iterate itemsの略?) を使えば順繰りにKeyとValueをリストアップすることが出来ます。

>>> for i, v in enumerate(['tic', 'tac', 'toe']):
...     print i, v
... 
0 tic
1 tac
2 toe


こちらはとても便利です。私は日頃Javaで開発をしていますが、Javaでは

String[] names = new String[] {"tic", "tac", "toe"};
for(String name : names) {
    Log.d("TEST", name);
}


と書くとループカウンタを別途用意しないといけません。なので結局は

String[] names = new String[] {"tic", "tac", "toe"};
for(int i; i < names.size(); i ++) {
    String name = names.get(i);
    Log.d("TEST", i + " " + name);
}


と書いてしまいます。


閑話休題。複数のリストを同時にループで回す場合はzip()関数が便利です。

>>> questions = ['name', 'quest', 'favarite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
...     print 'What is your {0}? It is {1}.'.format(q, a)
... 
What is your name? It is lancelot.
What is your quest? It is the holy grail.
What is your favarite color? It is blue.


またリストを逆順にループする場合はreversed()関数を使います。

>>> for i in reversed([1, 3, 5, 7, 9]):
...     print i
... 
9
7
5
3
1


最後にリストを昇順にループする方法。sorted()関数を使います。

>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
...     print f
... 
apple
banana
orange
pear


ちなみにsorted()関数はオリジナルのリストには影響を与えません。

More on Conditions

ここではwhileやif文で利用する条件文についてもう少し詳しく勉強します。が、だいたいC言語の規則と同じですね。C言語と違うのは条件式の中で代入演算が使えないことでしょうかね。

Comparing Sequences and Other Types

ここではSequenceデータ型と他のデータ型を比較することを学習します。

>>> (1, 2, 3) < (1, 2, 4)
True
>>> [1, 2, 3] < [1, 2, 4]
True
>>> 'ABC' < 'C'
True
>>> 'C' < 'Pascal'
True
>>> 'Pascal' < 'Python'
True
>>> (1, 2, 3, 4) < (1, 2, 4)
True
>>> (1, 2) < (1, 2, -1)
True
>>> (1, 2, 3) == (1.0, 2.0, 3.0)
True
>>> (1, 2, ('aa', 'bb')) < (1, 2, ('abc', 'a'), 4)
True


1 == 1.0というのがちょっと驚きですが、まぁ全体的には納得出来ました。ただしリストとTupleや文字列の比較も出来ます。

>>> [1, 2, 3] < "123"
True
>>> "123" < (1, 2, 3)
True


リスト < 文字列 < Tupleの順番になります。