Pythonの配列(list)はたくさんできることがあって他の言語よりも扱いやすいな〜と思います。 なんとなく配列は使えるけど、もっと良い方法を探している方向けに書きます。 配列操作がわかってくるとPythonのコードもスッキリしてきますので、是非使いこなしていきましょう。
以下はPython3.6で動作確認しました。
出力や操作後の配列の中身は# >>
もしくは"""出力"""
で表現しています。
配列の宣言
空(から)の配列の宣言
arr = []
内包表記
# 月
month = [m for m in range(1, 13)]
# >> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
全て同じ値
zero = [0 for m in range(10)]
# >> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
こっちでも大丈夫
zero = [0] * 10
# >> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
奇数/偶数の配列を作る
奇数
odd = [i for i in range(1, 12, 2)]
# >> [1, 3, 5, 7, 9, 11]
偶数
even = [i for i in range(0, 12, 2)]
# >> [0, 2, 4, 6, 8, 10]
結合 +, extend()
arr1 = ['a', 'b', 'c']
arr2 = ['D', 'E', 'F']
# 結合
arr3 = arr1 + arr2
print(arr3)
# >> ['a', 'b', 'c', 'D', 'E', 'F']
arr1.extend(arr2)
print(arr1)
# >> ['a', 'b', 'c', 'D', 'E', 'F']
四則演算
内包表記を使って要素に対し四則演算できます。
arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[i + 100 for i in arr]
# => [100, 101, 102, 103, 104, 105, 106, 107, 108, 109]
[i * 3 for i in arr]
# => [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
numpy
numpyを使うと直感的に四則演算できます。 行列のベクトルとスカラーを理解してからだとより自在に扱えるようになるので、学習がオススメです。
import numpy as np
arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
arr = np.array(arr)
arr
# >> array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr + 1
# >> array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
arr / 10
# >> array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
arr + arr
# >> array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
要素を取得
[]に数値を入れるとそこの要素を取得できます。
先頭の要素は0番目で末尾はlen(arr) - 1
番目です。
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
# 先頭の要素
arr[0]
# >> 1
# 末尾の要素
arr[len(arr) - 1]
# >> 12
# これもOK
arr[-1]
# >> 12
配列のサイズを越えるとエラーがでます。
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
arr[100]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
最大 max/最小 min
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
max(arr)
# >> 12
min(arr)
# >> 1
何番目の要素か index
arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
arr1.index(3)
# >> 2
arr2 = ['苺', 'バナナ', 'apple']
arr2.index('apple')
# >> 2
要素がないときはエラー。
arr1.index(13)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: 13 is not in list
部分配列 [start:end:step]
部分配列は[start:end:step]
で簡単に分けられます。
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
arr[6:]
# >> [7, 8, 9, 10, 11, 12]
arr[:7]
# >> [1, 2, 3, 4, 5, 6, 7]
arr[::2]
# >> [1, 3, 5, 7, 9, 11]
arr[1::2]
# >> [2, 4, 6, 8, 10, 12]
条件判定
要素を含むか in / not in
if文などの条件式で手軽に判定できます。
# 奇数
odd = [e for e in range(1, 12, 2)]
# >> [1, 3, 5, 7, 9, 11]
print( 5 in odd )
# >> True
print( 2 in odd )
# >> False
print( 2 not in odd )
# >> True
順序の変更
昇順/降順 list.sort() sorted()
要素の値によって昇順/降順できます。 数値だけでなく文字(文字列)や日付(datetime)もソートできます。
昇順
arr = [12, 9, 3, 2, 5, 1, 10, 7, 6, 8, 4, 11]
sorted(arr)
# >> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
arr
# >> [12, 9, 3, 2, 5, 1, 10, 7, 6, 8, 4, 11]
arr.sort()
arr
# >> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
sorted()
は新しくソートした配列を作成するのに対し、.sort()
は対象の配列をソートして更新します。s
降順 reverse=True
を指定する。
arr = [12, 9, 3, 2, 5, 1, 10, 7, 6, 8, 4, 11]
sorted(arr, reverse=True)
# >> [12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
arr
# >> [12, 9, 3, 2, 5, 1, 10, 7, 6, 8, 4, 11]
arr.sort(reverse=True)
arr
# >> [12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
逆順 list.reverse()
arr.reverse()
arr
# >> [12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
シャッフル
標準のrandom
モジュールを使う。
import random
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
random.shuffle(arr)
arr
# >> [11, 2, 5, 12, 9, 3, 10, 7, 6, 4, 8, 1]
# 毎回異なる順序
random.shuffle(arr)
arr
# >> [8, 3, 2, 11, 9, 7, 12, 6, 5, 4, 1, 10]
値とインデックスを同時に扱う enumerate()
arr = ['a', 'b', 'c']
for i, val in enumerate(arr):
print(i, val)
"""出力
0 a
1 b
2 c
"""
同時に複数の配列を扱う zip()
zip()
は同時に2つ以上の配列が扱えます。
lower = ['a', 'b', 'c']
upper = ['A', 'B', 'C']
for l, u in zip(lower, upper):
print(l, u)
"""出力
a A
b B
c C
"""
配列の長さが異なる場合は、短い方に合わせられます。
lower = ['a', 'b', 'c']
upper = ['A', 'B', 'C', 'D']
for l, u in zip(lower, upper):
print(l, u)
"""出力
a A
b B
c C
"""
要素のフィルタリング
filter()
を使うと条件に合った要素だけ取り出せる。
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
under_5 = list(filter(lambda x: x < 5, arr))
print(under_5)
# >> [1, 2, 3, 4]
odd = list(filter(lambda x: x%2 == 1, arr))
print(odd)
# >> [1, 3, 5, 7, 9, 11]
lambda x
のx
は要素。
:
の後にくる条件式が正となるものが取り出せる。
内包表記でフィルタリング
内包表記もフィルタリングできる。 ifを加えて真となる要素だけ抽出。
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
even = [x for x in arr if x%2 == 0]
# >> [2, 4, 6, 8, 10, 12]
空文字の要素を取り除く
ファイルを読み込んでからリスト化すると改行コードや空文字が含まれていたりします。
文字列の前後の空文字などを除去するstrip()
とfilter()
を使えば2行でかけました。
# 空文字などが混ざった配列
arr = ['2019\n',' \n', '01\n', ' suzu6\n', '\n', ' ']
dst = [x.strip() for x in arr]
# >> ['2019', '', '01', 'suzu6', '', '']
dst = list(filter(None, dst))
# >> ['2019', '01', 'suzu6']
空文字に値するものだけ取り除く場合はこちらもできる。
arr = ['2019\n',' \n', '01\n', ' suzu6\n', '\n', ' ']
dst = [x for x in arr if x.strip() is not '']
# >> ['2019\n', '12\n', ' suzu\n']
重複する要素の削除
集合(set)にすると重複する要素を削除できます。
upper = ['A', 'B', 'C', 'D', 'B', 'D', 'B', 'C', 'D']
result = list(set(upper))
result
# >> ['A', 'B', 'D', 'C']
要素の数を求める
upper = ['A', 'B', 'C', 'D', 'B', 'D', 'B', 'C', 'D']
upper.count('A')
# >> 1
upper.count('B')
# >> 3
要素の数を全て求めてdictにする
result = {}
upper = ['A', 'B', 'C', 'D', 'B', 'D', 'B', 'C', 'D']
for c in set(upper):
result[c] = upper.count(c)
print(result)
# >> {'A': 1, 'B': 3, 'D': 3, 'C': 2}
標準モジュールのcollections
を使うともっと簡単です。
import collections
upper = ['A', 'B', 'C', 'D', 'B', 'D', 'B', 'C', 'D']
result = collections.Counter(upper)
print(result)
# >> Counter({'B': 3, 'D': 3, 'C': 2, 'A': 1})
print(dict(result))
# >> {'A': 1, 'B': 3, 'C': 2, 'D': 3}
collections
についてはPythonのCounterでリストの各要素の出現個数をカウント - note.nkmk.meが詳しい。
区切り文字 <-> 配列
CSVやExcelのデータを扱うときに便利。
区切り文字 -> 配列
split()
を使う。カンマ区切りは','
で分けられます。
string = "a,b,c,d,e"
string.split(',')
# >> ['a', 'b', 'c', 'd', 'e']
区切り文字 <- 配列
"".join()
を使う。
カンマ区切りへは','
で変換できます。
arr = ['a', 'b', 'c', 'd', 'e']
"".join(arr)
# >> 'abcde'
",".join(arr)
# >> 'a,b,c,d,e'
文字列 <-> 配列
文字列(str型)も配列のように[:]で扱えますが、配列の関数をlist()
に入れ込めばlist型にできます。
string = 'Hello World'
print(string.split())
# >> ['Hello', 'World']
arr = list(string)
# >> ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']
''.join(arr)
# >> 'Hello World'
要素をそれぞれ処理する
配列の要素をそれぞれ処理したいときは結構あります。
for文よりもmap
を使うと簡潔に早く処理できます。
内包表記でも構いません。
例えば、要素を全て文字にする場合
for文
arr = [1, 2, 3, 4, 5]
# for
for i, n in enumerate(arr):
arr[i] = str(n)
print(arr)
# >> ['1', '2', '3', '4', '5']
内包表記
arr = [1, 2, 3, 4, 5]
arr = [str(i) for i in arr]
print(arr)
# >> ['1', '2', '3', '4', '5']
map
arr = [1, 2, 3, 4, 5]
arr = list(map(str, arr))
print(arr)
# >> ['1', '2', '3', '4', '5']
自作の関数で処理をする
ファイルのリストを作成して中身を配列に格納したいときなど、自作の関数を処理したいこともあります。 内包表記とmapでやってみる。
def read_csv(filename):
# ファイルの中身を読み込んで返す関数
with open(filename, mode='r') as file:
return file.read()
file_list = ['./2017/01.csv', './2017/02.csv', './2017/03.csv']
# 内包表記
arr = [read_csv(filename) for filename in file_list]
# map
arr = list(map(read_csv, file_list))
その他
参考
以下はこの記事を書く上で参考にした記事や参考書です。
オンライン学習
Udemy Python3の入門オンライン講座 Udemy Pythonコース