はじめに
このセクションでは、リスト、辞書、セットについて説明します。
概要
プログラムは多くのオブジェクトとともに動作することがよくあります。
- 株式のポートフォリオ
- 株価のテーブル
使用する主な選択肢は 3 つあります。
- リスト。順序付きデータ。
- 辞書。順序なしデータ。
- セット。一意の要素の順序なしコレクション。
コンテナとしてのリスト
データの順序が重要な場合にはリストを使用します。リストは任意の種類のオブジェクトを保持できることを忘れないでください。たとえば、タプルのリストです。
portfolio = [
('GOOG', 100, 490.1),
('IBM', 50, 91.3),
('CAT', 150, 83.44)
]
portfolio[0] ## ('GOOG', 100, 490.1)
portfolio[2] ## ('CAT', 150, 83.44)
リストの作成
ゼロからリストを作成する。
records = [] ## 初期の空のリスト
#.append() を使用して項目を追加する
records.append(('GOOG', 100, 490.10))
records.append(('IBM', 50, 91.3))
...
ファイルからレコードを読み取る場合の例。
records = [] ## 初期の空のリスト
with open('portfolio.csv', 'rt') as f:
next(f) ## ヘッダーをスキップする
for line in f:
row = line.split(',')
records.append((row[0], int(row[1]), float(row[2])))
コンテナとしての辞書
キー名による高速なランダム検索が必要な場合は、辞書が便利です。たとえば、株価の辞書です。
prices = {
'GOOG': 513.25,
'CAT': 87.22,
'IBM': 93.37,
'MSFT': 44.12
}
以下はいくつかの簡単な検索です。
>>> prices['IBM']
93.37
>>> prices['GOOG']
513.25
>>>
辞書の作成
ゼロから辞書を作成する例。
prices = {} ## 初期の空の辞書
## 新しい項目を挿入する
prices['GOOG'] = 513.25
prices['CAT'] = 87.22
prices['IBM'] = 93.37
ファイルの内容から辞書を作成する例。
prices = {} ## 初期の空の辞書
with open('prices.csv', 'rt') as f:
for line in f:
row = line.split(',')
prices[row[0]] = float(row[1])
注:prices.csv ファイルでこれを試すと、ほぼ機能することがわかります。ただし、末尾に空行があるため、コードがクラッシュします。それに対応するためのコードを修正する方法を考える必要があります(演習 2.6 を参照)。
辞書の検索
キーの存在をテストできます。
if key in d:
## はい
else:
## いいえ
存在しない可能性のある値を検索し、存在しない場合にデフォルト値を提供できます。
name = d.get(key, default)
例:
>>> prices.get('IBM', 0.0)
93.37
>>> prices.get('SCOX', 0.0)
0.0
>>>
複合キー
Python では、ほとんどどんな型の値でも辞書のキーとして使用できます。辞書のキーは、不変な型でなければなりません。たとえば、タプルです。
holidays = {
(1, 1) : 'New Years',
(3, 14) : 'Pi day',
(9, 13) : "Programmer's day",
}
そして、アクセスするには:
>>> holidays[3, 14]
'Pi day'
>>>
リスト、セット、または別の辞書は、辞書のキーとして機能することはできません。なぜなら、リストと辞書は可変であるからです。
セット
セットは、順序がなく、重複しない要素のコレクションです。
tech_stocks = { 'IBM','AAPL','MSFT' }
## 別の構文
tech_stocks = set(['IBM', 'AAPL', 'MSFT'])
セットは、メンバーシップテストに便利です。
>>> tech_stocks
set(['AAPL', 'IBM', 'MSFT'])
>>> 'IBM' in tech_stocks
True
>>> 'FB' in tech_stocks
False
>>>
セットは、重複削除にも便利です。
names = ['IBM', 'AAPL', 'GOOG', 'IBM', 'GOOG', 'YHOO']
unique = set(names)
## unique = set(['IBM', 'AAPL','GOOG','YHOO'])
追加のセット演算:
unique.add('CAT') ## 要素を追加する
unique.remove('YHOO') ## 要素を削除する
s1 = { 'a', 'b', 'c'}
s2 = { 'c', 'd' }
s1 | s2 ## セットの和集合 { 'a', 'b', 'c', 'd' }
s1 & s2 ## セットの積集合 { 'c' }
s1 - s2 ## セットの差集合 { 'a', 'b' }
これらの演習では、このコースの残りの部分で使用される主要なプログラムの 1 つを作成し始めます。report.py ファイルで作業してください。
演習 2.4:タプルのリスト
portfolio.csv ファイルには、ポートフォリオ内の株式のリストが含まれています。演習 1.30 では、このファイルを読み取り、単純な計算を行う関数 portfolio_cost(filename) を書きました。
あなたのコードはおそらくこのようになっているはずです。
## pcost.py
import csv
def portfolio_cost(filename):
'''ポートフォリオファイルの総コスト(株数 * 価格)を計算する'''
total_cost = 0.0
with open(filename, 'rt') as f:
rows = csv.reader(f)
headers = next(rows)
for row in rows:
nshares = int(row[1])
price = float(row[2])
total_cost += nshares * price
return total_cost
このコードを大まかなガイドとして、新しいファイル report.py を作成します。そのファイルに、与えられたポートフォリオファイルを開き、タプルのリストに読み込む関数 read_portfolio(filename) を定義します。これを行うには、上記のコードにいくつかの小さな修正を加えます。
まず、total_cost = 0 を定義する代わりに、最初に空のリストに設定される変数を作成します。たとえば:
portfolio = []
次に、コストを合算する代わりに、各行を前の演習とまったく同じようにタプルに変換し、このリストに追加します。たとえば:
for row in rows:
holding = (row[0], int(row[1]), float(row[2]))
portfolio.append(holding)
最後に、結果の portfolio リストを返します。
対話的に関数を試してみましょう(これを行うには、まずインタプリタで report.py プログラムを実行する必要があることに注意してください):
ヒント:端末でファイルを実行する際に -i を使用します
>>> portfolio = read_portfolio('/home/labex/project/portfolio.csv')
>>> portfolio
[('AA', 100, 32.2), ('IBM', 50, 91.1), ('CAT', 150, 83.44), ('MSFT', 200, 51.23),
('GE', 95, 40.37), ('MSFT', 50, 65.1), ('IBM', 100, 70.44)]
>>>
>>> portfolio[0]
('AA', 100, 32.2)
>>> portfolio[1]
('IBM', 50, 91.1)
>>> portfolio[1][1]
50
>>> total = 0.0
>>> for s in portfolio:
total += s[1] * s[2]
>>> print(total)
44671.15
>>>
あなたが作成したこのタプルのリストは、2 次元配列に非常に似ています。たとえば、portfolio[row][column] のような参照を使用して特定の列と行にアクセスできます。ここで row と column は整数です。
つまり、最後の for ループをこのような文を使って書き直すこともできます:
>>> total = 0.0
>>> for name, shares, price in portfolio:
total += shares*price
>>> print(total)
44671.15
>>>
演習 2.5:辞書のリスト
演習 2.4 で書いた関数を取り、ポートフォリオ内の各株式をタプルではなく辞書で表すように修正します。この辞書では、入力ファイルの異なる列を表すために、「name」、「shares」、「price」のフィールド名を使用します。
演習 2.4 と同じ方法でこの新しい関数を試してみましょう。
>>> portfolio = read_portfolio('/home/labex/project/portfolio.csv')
>>> portfolio
[{'name': 'AA','shares': 100, 'price': 32.2}, {'name': 'IBM','shares': 50, 'price': 91.1},
{'name': 'CAT','shares': 150, 'price': 83.44}, {'name': 'MSFT','shares': 200, 'price': 51.23},
{'name': 'GE','shares': 95, 'price': 40.37}, {'name': 'MSFT','shares': 50, 'price': 65.1},
{'name': 'IBM','shares': 100, 'price': 70.44}]
>>> portfolio[0]
{'name': 'AA','shares': 100, 'price': 32.2}
>>> portfolio[1]
{'name': 'IBM','shares': 50, 'price': 91.1}
>>> portfolio[1]['shares']
50
>>> total = 0.0
>>> for s in portfolio:
total += s['shares']*s['price']
>>> print(total)
44671.15
>>>
ここでは、各エントリの異なるフィールドには、数値の列番号ではなくキー名を使ってアクセスすることがわかります。これは、結果のコードが後で読みやすくなるため、多くの場合好まれます。
大きな辞書やリストを表示すると混乱する場合があります。デバッグ用に出力を整理するには、pprint 関数を使用することを検討してください。
>>> from pprint import pprint
>>> pprint(portfolio)
[{'name': 'AA', 'price': 32.2,'shares': 100},
{'name': 'IBM', 'price': 91.1,'shares': 50},
{'name': 'CAT', 'price': 83.44,'shares': 150},
{'name': 'MSFT', 'price': 51.23,'shares': 200},
{'name': 'GE', 'price': 40.37,'shares': 95},
{'name': 'MSFT', 'price': 65.1,'shares': 50},
{'name': 'IBM', 'price': 70.44,'shares': 100}]
>>>
演習 2.6:辞書をコンテナとして使用する
辞書は、整数以外のインデックスを使って項目を検索したい場合に便利な方法です。Python シェルで辞書を試してみましょう:
>>> prices = { }
>>> prices['IBM'] = 92.45
>>> prices['MSFT'] = 45.12
>>> prices
... 結果を見る...
>>> prices['IBM']
92.45
>>> prices['AAPL']
... 結果を見る...
>>> 'AAPL' in prices
False
>>>
prices.csv ファイルには、株価の一連の行が含まれています。このファイルはこのようになっています:
"AA",9.22
"AXP",24.85
"BA",44.85
"BAC",11.27
"C",3.72
...
辞書のキーが株式名で、辞書の値が株価であるように、このような価格のセットを読み取る関数 read_prices(filename) を書きましょう。
これを行うには、空の辞書から始めて、上記と同じように値を挿入し始めます。ただし、今回はファイルから値を読み取っています。
このデータ構造を使って、与えられた株式名の価格を迅速に検索します。
この部分で必要になるいくつかの小さなヒントがあります。まず、前と同じように csv モジュールを使うことを確認してください。ここでは再発明する必要はありません。
>>> import csv
>>> f = open('/home/labex/project/prices.csv', 'r')
>>> rows = csv.reader(f)
>>> for row in rows:
print(row)
['AA', '9.22']
['AXP', '24.85']
...
[]
>>>
もう 1 つの小さな問題は、prices.csv ファイルに空行が含まれている可能性があることです。上記のデータの最後の行が空のリストであることに注意してください。これは、その行にデータが存在しなかったことを意味します。
これがプログラムを例外で終了させる原因になる可能性があります。try と except 文を使って、適切にこれをキャッチしましょう。考えてみましょう:if 文を使って不適切なデータを防ぐ方が良いでしょうか?
read_prices() 関数を書いたら、対話的にテストして、機能することを確認しましょう:
>>> prices = read_prices('/home/labex/project/prices.csv')
>>> prices['IBM']
106.28
>>> prices['MSFT']
20.89
>>>
演習 2.7:退職できるかどうかを調べる
損益を計算する追加の文を report.py プログラムに追加することで、これらの作業すべてをまとめましょう。これらの文は、演習 2.5 の株式のリストと演習 2.6 の価格の辞書を使って、ポートフォリオの現在の価値と損益を計算する必要があります。
まとめ
おめでとうございます!あなたはコンテナの実験を完了しました。あなたのスキルを向上させるために、LabEx でさらに多くの実験を行って練習することができます。