シリーズ「Pythonプログラミングの始め方」では、Pythonの基礎文法を図を用いて分かりやすく解説していきます。
前回の記事では、Pythonのデータ構造の1つであるリスト<List>の扱い方の基本を紹介しました。
リストは、[要素1, 要素2, ・・・]のように、”[]”(角カッコ)の中に要素が“,”(カンマ)区切りで並びます。リストは、ミュータブル(mutable)なデータ構造で、要素の追加・更新・削除を自由に行うことができるのでした。
List(リスト)の定義(生成)方法、参照と更新、連結といった基本操作については以下の記事を参考にしてください。
さて今回は、リストの使い方の【応用編】として、リストオブジェクトが提供するさまざまな機能について解説を進めたいと思います。Pythonで多用されるリストには、さまざまな操作を効率的に行うためのメソッドが予め用意されています。
たとえば、、
- リストに要素を追加する
- リストから特定の要素を抜き取る(削除する)
- 要素を並び替える
- 特定の要素を探索・調査する ・・・
などです。ですので自身でコーディングする前に、Python(リスト)が提供する機能やメソッドが存在しないか調べ、あれば積極的に活用すべきだと筆者は考えます。
本記事は、数あるリスト系メソッドの中から「要素を並び替える」「特定の要素を探索・調査する」について解説します。
重要度:★★★★☆
なお、詳細については公式ドキュメント「Python標準ライブラリ」(シーケンス型・ミュータブル)に記載内容も併せて確認頂きたくよろしくお願いいたします。
Python標準ライブラリ シーケンス型(ミュータブル)
https://docs.python.org/ja/3/library/stdtypes.html#mutable-sequence-types
1. 要素を並び替え/調べる(sort, reverse)
本節では、要素を並び替えるためのメソッド(sort()/reverse())と標準関数(sorted()/reversed())を紹介します。その他、Pythonの標準機能を使った方法についても併せて解説します。
1.1 昇/降順または任意の順に並べる(1): sort()
リストの要素をソート (整列)させるためのメソッドに sort() があります。書式は次の通りで、引数などで特に整列方法をしてしなければ(デフォルト)、数値は昇順、文字列は文字コードに準拠した順番に並び替え(ソート)させます。また、 戻り値はなく元のリストそのものに変更を加える不可逆的な処理を行います。
引数は、オプショナルで特に何もしていしなければ数値や文字コードで昇順にソートされますが、引数:reverse に“True”を設定することで降順にソートすることができます。また、引数:key には、ソートの基準となる関数やメソッドを指定することができます。特に指定しなければ値やオブジェクトの大小関係で比較されますが、文字数や大文字、小文字での比較などカスタムしたい場合には明示します。たとえば、 引数:key には次のように指定できます。
機能 | 指定方法 | 補足事項 |
---|---|---|
文字数で整列 | key = len | 標準関数:len() |
絶対値で整列 | key = abs | 標準関数:abs() |
インデックスで整列 | key = index | Listオブジェクトのindex()メソッド |
小文字基準で整列 | key = str.lower | Stringオブジェクトのlower()メソッド |
関数・メソッド名は「()」なしで指定します。また、既存の関数だけではなく、自身で定義したメソッド(def文)を指定したり、「lambda式」を直接書き込みます。
次は、sort()メソッドの使用例です。数値・文字列が混載された状態でもソートできます。その場合は、数値が優先されます。また、文字列は大文字が優先されます。(共に昇順の場合、降順の場合はその逆です) <List1>
# sort()メソッドのソート例
# 昇順に(元リストを)並び替える-------------------------------
# リスト(数値)
numbers = [24, 45, 12, 9, 4, 35]
numbers.sort()
print(numbers) # ➀>> [4, 9, 12, 24, 35, 45]
# リスト(文字列)
words = ['s','z', 'e', 'a', 'q', 'r' ]
words.sort()
print(words) # ➁>> ['a', 'e', 'q', 'r', 's', 'z']
# リスト(数値, 文字列 混載)
number_word = ['Abc', 'abc', '3', '1']
number_word.sort()
print(number_word) # ➂>> ['1', '3', 'Abc', 'abc']
# 降順に(元リストを)並び替える-------------------------------
numbers = [24, 45, 12, 9, 4, 35]
numbers.sort(reverse = True)
print(numbers) # ➃>> [45, 35, 24, 12, 9, 4]
number_word = ['Abc', 'abc', '3', '1']
number_word.sort(reverse = True)
print(number_word) # ➄>> ['abc', 'Abc', '3', '1']
sort()メソッド の実行結果(1)
昇順に(元リストを)並び替える
➀》[4, 9, 12, 24, 35, 45]
➁》[‘a’, ‘e’, ‘q’, ‘r’, ‘s’, ‘z’]
➂》[‘1’, ‘3’, ‘Abc’, ‘abc’]
降順に(元リストを)並び替える
➃》[45, 35, 24, 12, 9, 4]
➄》[‘abc’, ‘Abc’, ‘3’, ‘1’]
次は、引数:key にソート方法の基準をする例です。標準関数(➀,②)を採ったり、ユーザ定義関数(ここではlambda式 ➂)にて対応した例です。<List2>
# sort()メソッドの実行例(key指定)
# サイズで比較ソート -------------------------------------------
words = ['a','aa', 'b', 'c', 'd']
words .sort(key=len)
print(words)
# ➀>>['a', 'b', 'c', 'd', 'aa'] ※key=lenを省略した場合:['a', 'aa', 'b', 'c', 'd']
# 絶対値で比較ソート -------------------------------------------
numbers = [24, -45, 12, -9, 4, 35]
numbers.sort(key=abs)
print(numbers)
# ➁>>[4, -9, 12, 24, 35, -45] ※key=absを省略した場合:[-45, -9, 4, 12, 24, 35]
# 定義した関数(lambda式)で比較ソート ----------------------------
index_list = ['梅','竹', '松']
data = ['梅','竹', '松', '梅','竹', '松', '梅','竹', '松']
data.sort(key = lambda x : index_list.index(x))
print(data)
# ➂>>['梅', '梅', '梅', '竹', '竹', '竹', '松', '松', '松'] ※keyを省略した場合:['松', '松', '松', '梅', '梅', '梅', '竹', '竹', '竹']
sort()メソッド の実行結果(2)
➀》[‘a’, ‘b’, ‘c’, ‘d’, ‘aa’] ※key=lenを省略した場合:[‘a’, ‘aa’, ‘b’, ‘c’, ‘d’]
➁》[4, -9, 12, 24, 35, -45] ※key=absを省略した場合:[-45, -9, 4, 12, 24, 35]
➂》[‘梅’, ‘梅’, ‘梅’, ‘竹’, ‘竹’, ‘竹’, ‘松’, ‘松’, ‘松’] ※keyを省略した場合:[‘松’, ‘松’, ‘松’, ‘梅’, ‘梅’, ‘梅’, ‘竹’, ‘竹’, ‘竹’]
1.2 昇/降順または任意の順に並べる(2): sorted関数
1.1項のsort()メソッドと同じ機能を提供する標準関数 sorted()関数 もあります。
ただし sorted() は整列された新しいリストを返し、元のリストへ変更を加えません(可逆的処理)。そのため、イミュータブルなオブジェクト(文字列やタプル)のソートが可能となります(戻り値はリストになることは注意)。
次は、sorted()関数の使用例です。ミュータブルなオブジェクトもソートできますが、戻り値はリストとなりますので注意してください。この例ではtuple関数でリストをタプルに変換、元のデータ構造に戻しています。<List3>
# sorted()関数の使用例
# リスト
numbers = [24, 45, 12, 9, 4, 35]
list_sorted = sorted(numbers)
print(list_sorted) # ➀>> [4, 9, 12, 24, 35, 45]
print(numbers) # ➁>> [24, 45, 12, 9, 4, 35]
# タプル
numbers = (24, 45, 12, 9, 4, 35)
tuple_sorted = sorted(numbers)
print(tuple(tuple_sorted)) # ➀>> (4, 9, 12, 24, 35, 45)
print(numbers) # ➁>> (24, 45, 12, 9, 4, 35)
1.3 要素の並びを逆順にする(1): reverse()
リストの要素を逆順(インデックス)に並び替えるメソッドに reverse() があります。書式は次の通りで、戻り値はなく元のリストそのものに変更を加える不可逆的な処理を行います。従って、イミュータブルなオブジェクト(タプルや文字列)に対する本メソッドはありません。
reverse() メソッドの使用例を示します。元のリストに変更を加えます。
# reverse()メソッドの使用例
numbers = [24, 45, 12, 9, 4, 35] # 初期リスト
strings = ['A', 'B', 'C']
# 要素(整数)を並びを逆順にする
numbers.reverse()
print(numbers) # ➀>> [35, 4, 9, 12, 45, 24] 要素の並びが逆順になった
# 要素(文字列)を並びを逆順にする
strings.reverse()
print(strings) # ➁>> ['C', 'B', 'A']
reverse() メソッドの実行結果(要素を並びを逆順にする)
➀》[35, 4, 9, 12, 45, 24]
➁》[‘C’, ‘B’, ‘A’]
要素を並び替えるのであれば、リストのスライス機能を使う方法もあります。対象のオブジェクトに対して[::-1]を付加するだけで対応できます(開始、終了を両略、ステップに-1を指定)。さらに、スライスは、元のオブジェクトのコピーに対して処理を行う非破壊処理となります。そのため、イミュータブルなオブジェクト(タプルや文字列)にも対応します。
# スライスを使った要素の並び替え
num_list = [24, 45, 12, 9, 4, 35]
num_tuple = (24, 45, 12, 9, 4, 35)
print(num_list[::-1])
# ➀>>[35, 4, 9, 12, 45, 24]
# スライスは、非破壊処理なのでイミュータブル(タプルや文字列)にも適用できる
# タプルの並び替え
print(num_tuple[::-1])
# ➁>>(35, 4, 9, 12, 45, 24)
# 文字列の並び替え
print("Python"[::-1])
# ➂>>nohtyP
”スライス”による要素を並び替え(逆順)
➀》[35, 4, 9, 12, 45, 24]
➁》(35, 4, 9, 12, 45, 24)
➂》nohtyP
1.4 要素の並びを逆順にする(2): reversed関数
リストの要素を逆順(インデックス)に並び替えるもう一つの方法に、組込み関数 reversed() を使うといったものがあります。書式は次の通りで、先の reverse() メソッドと異なり元のリストを変更しない非破壊処理となります。そのため、reversed() 関数では、タプルや文字列なども扱うことができます。戻り値は、特定の型のオブジェクトではなくイテレータを戻します。
reversed() 関数の使用例を示します。戻り値は、イテレータとなります(➀,②)ので、内包表記(for文)などで展開できますし、任意のデータ構造(リストやタプルなど)に変換できます。(➂,④)
# reversed関数の使用例
numbers = [24, 45, 12, 9, 4, 35] # 初期リスト
# reversed関数は、イテレータを戻り値とする
print(reversed(numbers))
# ➀>><list_reverseiterator object at 0x000001D023A64088>
print(type(reversed(numbers)))
# ➁>><class 'list_reverseiterator'>
# リストとして取得したい場合は、内包表記やlist()関数で変換する
print([num for num in reversed(numbers)])
print(list(reversed(numbers)))
# ➂>>[35, 4, 9, 12, 45, 24]
# タプルとして取得したい場合は、tuple()関数で変換する
print(tuple(reversed(numbers)))
# ➃>>(35, 4, 9, 12, 45, 24)
reversed関数 の実行結果(要素を並びを逆順にする)
➀》list_reverseiterator object at 0x000001D0238BCE88
➁》class ‘list_reverseiterator‘
➂》[35, 4, 9, 12, 45, 24]
➃》(35, 4, 9, 12, 45, 24)
2. 要素の属性を調べる(index, count)
本節では、要素の位置や出現回数といった属性を調べるためのメソッド(index/count)や関数(len)を紹介します。その他、Pythonの標準機能を使った方法についても併せて解説します。
2.1 要素の位置(インデックス)を調べる: index()
リストの特定要素の位置(インデックス)を調べるメソッドに index() があります。書式と概略図は次のとおりで、引数に目的の要素(値)を指定します。
リストに、対象の要素(値)が複数が複数含まれている場合は、最初に見つかったインデックスを返します。また、リストにない要素を指定するとエラー(ValueError)となります。
Index()メソッドの使用例を示します。特定の要素を指定してインデックスを調べています。要素(“orange”)は、2つありますが (1, 5番目)最初に見つかったインデックスを返します。(➂)また、➃では存在しない要素(“xyz”)を指定したためValueErrorが発生しています、予め「in」ステートメントなどで存在を確認後実行するのがよいでしょう。
# index()メソッドの使用例
list_A = ["apple", "orange", 123, "banana", "remon", "orange"]
# 要素のインデックスを調べる
print(list_A.index("apple")) # ➀>> 0 インデックス0の要素
print(list_A.index(123)) # ➁>> 2 インデックス2の要素
print(list_A.index("orange")) # ➂>> 1 最初に見つかったインデックスを返す
#-------------------------------------------------------------------
# リストに存在しない場合はエラーが発生する
#print(list_A.index("xyz")) # ➃>> ValueError: 'xyz' is not in list
if "xyz" in list_A:
print(list_A.index("xyz"))
index() の実行結果
➀》0
➁》2
➂》1
➃》ValueError: ‘xyz’ is not in list
なお、同じ要素が複数含まれるリストのインデックスを全て調べる場合には、組込み関数「enumerate」と内包表記とを組合わせること対応できる。また、要素が見つからない場合もエラーとはならず空リストが戻る。
<内包表記:内包表記でリスト・辞書・セットの定義をスマートに>
# 同じ要素を複数含むリストのインデックスを返す
print([inx for inx, val in enumerate(list_A) if val == 'orange'])
# ➀>> [1, 5]
# 存在しない要素を指定してもエラーにならない
print([inx for inx, val in enumerate(list_A) if val == 'xyz'])
# ➁>> []
2.2 特定の要素の個数を調べる: count()
リスト内に特定の要素が何個含まれているかを調べる方法のひとつに count()メソッド があります。書式と概略図は次のとおりです。
引数に指定した要素(値)をカウントし、部分一致ではなく完全一致したものをカウントします。たとえば、「a」[aa]の要素は別物としてカウントします。なお、リスト中に存在しなかった場合は0を戻します。(エラーとはなりません)シーケンス型であれば良いので、リストに限らずタプルや文字列にも適用できます。
次は count()メソッドの使用例を示します。リスト中に存在しない値を指定してもエラーとはならずに0が戻ります。また、「a」[aa][ab]などは別ものとして認識され完全一致した値のみをカウントしていることが確認できます。
# count()メソッドの使用例
numbers = [1, 2, 2, 3, 3, 3, 4, 5, 6]
print(numbers.count(1)) # >> 1
print(numbers.count(2)) # >> 2
print(numbers.count(3)) # >> 3
print(numbers.count(9)) # >> 0
#-------------------------------------------------------------------
words = ['a','a','a','aa','ab','b','b','c','e', 1]
print(words.count('a')) # >>3 完全一致した場合カウントする'aa', 'ab'など部分一致はカントしない
print(words.count('aa')) # >>1
print(words.count('ab')) # >>1
print(words.count('b')) # >>2
print(words.count(1)) # >>1 文字・数値が混在したリストからでもカウントすることができる
また、次は文字列オブジェクトに対する count()メソッドの適用例です。但し、文字列の場合は、第2,3引数で探索範囲指定(開始, 終了位置)ができます。範囲指定は、スライスと同じで、省略すると最初(最後)、負数での指定もできます。
# 文字列オブジェクトに対する、count()メソッドの適用
s = 'I am learning Python.I am learning Python.'
print(s.count('I')) # >>2
print(s.count('a')) # >>4
print(s.count('am')) # >>2
# 文字列の場合は、第2,3引数により範囲指定ができる
# 範囲指定は、スライスと同じ、省略すると最初(最後)、負数でも指定できる
print(s.count('I', 0, 20)) # >>1
print(s.count('I', 21,-1)) # >>1
補足として、リストオブジェクトのメソッドではありませんが、要素ごとの出現回数を数え上げる関連モジュール(collections)の Counterクラス を紹介します。
count()メソッドは、要素ごとに調べる必要がありますが、collections.Counter()は一度に全ての要素について調べることができます。dict型のサブクラスとして辞書の戻り値とし、辞書型の各種メソッドで扱えます。
import collections
words = ['a','a','a','aa','ab','b','b','c','e', 1]
cnt = collections.Counter(words)
print(cnt)
# >>Counter({'a': 3, 'b': 2, 'aa': 1, 'ab': 1, 'c': 1, 'e': 1, 1: 1})
print(type(cnt))
# >><class 'collections.Counter'>
print(cnt.keys())
# >>dict_keys(['a', 'aa', 'ab', 'b', 'c', 'e', 1])
print(cnt.values())
# >>dict_values([3, 1, 1, 2, 1, 1, 1])
print(cnt.items())
# >>dict_items([('a', 3), ('aa', 1), ('ab', 1), ('b', 2), ('c', 1), ('e', 1), (1, 1)])
2.3 リストの要素数を調べる:len()関数
単純にリストの要素数を調べるのであれば、組込み関数の len() を使います。
リスト型に限らずシーケンス型のオブジェクト全般についてサイズ(要素数・文字数)を取得できます。
# len()関数
# リストの要素数
l = [1, 2, 3, 4, 5, 6]
print(len(l))
# >>6
# タプルの要素数
t = (1, 2, 3, 4, 5, 6)
print(len(t))
# >>6
# セットの要素数
s = {1, 2, 3, 4, 5, 6}
print(len(s))
# >>6
# 辞書の要素数
d = {'key1':1, 'key2':2, 'key3':2}
print(len(d))
# >>3
# 文字列の文字数
st = "Python"
print(len(st))
# >>6
3. まとめ
いかがでしたでしょうか。
今回は、リストの使い方の【応用編】として、リストオブジェクトが提供する数あるメソッドの中から「要素を並び替える」「特定の要素を探索・調査する」について解説してきました。
自身でコーディングする前に、Python(リスト)が提供する機能やメソッドが存在しないか調べ、あれば積極的に活用していきましょう。
最後に、ポイントを確認しておきましょう。
「Listオブジェクト」には、操作を効率的に行うためのメソッドが提供されている
上記以外にも、要素の追加・削除・抜き取りなどのカテゴリがある。
リストの基本操作として参照や更新・連結・比較についての関連記事については、こちらを参照していただければと思います。
最後までお読みいただきありがとうございました。