【Pythonデータ構造】List(リスト)の参照と更新~連結・比較までを図解で詳解

スポンサーリンク
Pythonの基礎文法(リスト・参照・連結・比較) Python

Pythonの基礎文法を図を用いて分かりやすく解説していきます。

今回はPythonのデータ構造の一つであるリスト<list>の応用操作として、「➀リストの参照と更新をする方法」、「➁リスト同士を連結・複製・比較」を解説します。

➀ リストの参照と更新をする方法

➁ リスト同士を連結・比較する方法

リストを生成する方法と関連するメソッドに関しては、次の関連記事で解説していますのでこちらを参照してください。

スポンサーリンク

1. リストの参照と更新

Python_基礎構文(List)_参照

関連記事(リストの生成と関連メソッド)でも触れましたが、リストを構成する要素はインデックスという識別子が割り振られています。

また、インデックスは基準を前方からとる場合と後方からとる場合の2通りで指定することができす。

どちらかでも意味は同じですが、前方から指定する場合はインデックスは先頭の要素を「0」とし以降昇順に割り振られます。後方から指定する場合は、末尾を「-1」として先頭の要素に向かって[-2][-3] ・・・と続きます。

リストの書式(2)
図1 リストのインデックス指定

つまり、リストオブジェクトに続けて[インデックス]で参照します。

1.1 単純(1次元)リストの参照と更新

単純(1次元)リストの各要素にはインデックスを用いて次の書式と実行例のようにして参照します。

インデックス指定した要素の参照と更新

リスト名index


引数:index:要素の参照位置、基準の取り方によって前方指定、後方指定2通りのある。

  • 前方指定:要素の先頭から0、1、2、3、4・・・
  • 後方指定:要素の末尾から-1、-2、-3、-4、-5・・・

各要素の参照・更新をインデックスの前方向基準と後方基準それぞれで実行している例です。

# 単純(一次)リストの参照と更新

#--------------------------------------------------------------------
# インデックスをつかったリストの参照

words = ["blue", "red", "green", "yellow"] # 元のリスト

#インデックスを前方基準で参照する場合

print(words[0])     # >>blue  先頭の要素のインデックスを「0」とする
print(words[1])     # >>red
print(words[2])     # >>green
print(words[3])     # >>yellow


#インデックスを後方基準で参照する場合

print(words[-1])    # >>yellow 末尾の要素のインデックスを「-1」とする
print(words[-2])    # >>green
print(words[-3])    # >>red
print(words[-4])    # >>blue

print(words)        # >>['blue', 'red', 'green', 'yellow'] 元のリストは維持される

#--------------------------------------------------------------------
# インデックスをつかったリストの更新

words[0] = 1234    # >>先頭要素を「1234」に切り替える
print(words)       # >>[1234, 'red', 'green', 'yellow'] 先頭要素が「1234」に更新

words[-1] = 4321    # >>末尾の要素を「4321」に切り替える
print(words)       # >>[1234, 'red', 'green', 4321] 先頭要素が「4321」に更新

1.2 多重リストの参照と更新

リストの要素にはさらにリストを設定することもできます。下記は2次元リストの概要になりますが、外側のリストの要素(親要素)と内側のリストの要素(子要素)をそれぞれ個別にインデックス指定をします。書式は次のとおりです。

多重(2次元)リストの書式

リスト名[index1][index2]


引数:index1:外側(親要素)のインデックス

引数:index2:内側(子要素)のインデックス

※インデックスの指定基準は単純リストと同様です

2次元リストの構成
図22次元リストの概略図

2次元リストも単純(1次元)リスト同様に参照・更新することができます。コードの実行例は以下のとおりです。

# 多重リスト(2次元)の参照と更新

#--------------------------------------------------------------------
# 元のリスト
list_a = [["apple", "peach", "orange"], ["cabbage", "carrot", "potato"]]
print(list_a)   # >>[['apple', 'peach', 'orange'], ['cabbage', 'carrot', 'potato']]

#---------------------------------------------------------------------
# 親要素の参照

print(list_a[0])    # >>['apple', 'peach', 'orange']
print(list_a[1])    # >>['cabbage', 'carrot', 'potato']

#---------------------------------------------------------------------
# 子要素の参照

print(list_a[0][0]) # >> apple 親要素インデックス「0」の子要素の参照
print(list_a[0][1]) # >> peach
print(list_a[0][2]) # >> orange

print(list_a[1][0]) # >> cabbage 親要素インデックス「1」の子要素の参照
print(list_a[1][1]) # >> carrot
print(list_a[1][2]) # >> potato

#---------------------------------------------------------------------
# 親要素の更新

list_a[0] = [123, 456] # 親要素のインデックス「0」を更新
print(list_a) # >>[[123, 456], ['cabbage', 'carrot', 'potato']]

list_a[1][1] = 456 # 親要素のインデックス「1」、子要素のインデックス「1」を更新
print(list_a) # >>[[123, 456], ['cabbage', 456, 'potato']]

仕様上は作成できるリストの次数には上限はありませんのでさらに階層を掘り下げることができます。ですが、次数を増やすごとに複雑になり可読性の低下やバグの温床になるでの3次以降のリスト構造はあまり使わない方がベターです。

3次元リストの書式と概略図は以下のとおりになります。

多重(3次元)リストの書式

リスト名[index1][index2][index3]


引数:index1:外側(親要素)のインデックス

引数:index2:中側(子要素)のインデックス

引数:index3:内側(孫要素)のインデックス

※インデックスの指定基準は単純リストと同様です

3次元リストの構成
図3 3次元リストの概略図

3次元リストも単純(1次元)リスト同様に参照・更新することができ、コード実行例は下記のとおりです。

# 多重リスト(3次元)の参照と更新

#--------------------------------------------------------------------
# 元のリスト
list_b = [[["a", "b"], ["c", "d"]], [["e", "f"], ["g", "h"]]]
print(list_b) # >>[[['a', 'b'], ['c', 'd']], [['e', 'f'], ['g', 'h']]]

#---------------------------------------------------------------------
# 親要素の参照

print(list_b[0])        # >>[['a', 'b'], ['c', 'd']]
print(list_b[1])        # >>[['e', 'f'], ['g', 'h']]

#---------------------------------------------------------------------
# 子要素の参照

print(list_b[0][0])     # >>['a', 'b']
print(list_b[0][1])     # >>['c', 'd']
print(list_b[1][0])     # >>['e', 'f']
print(list_b[1][1])     # >>['g', 'h']

#---------------------------------------------------------------------
# 孫要素の参照

print(list_b[0][0][0])  # >>a
print(list_b[0][0][1])  # >>b
print(list_b[0][1][0])  # >>c
print(list_b[0][1][1])  # >>d
print(list_b[1][0][0])  # >>e
print(list_b[1][0][1])  # >>f
print(list_b[1][1][0])  # >>g
print(list_b[1][1][1])  # >>h

#---------------------------------------------------------------------
# 親要素の更新

list_b[0] = [1, [2, 3]]
print(list_b) # >>[[1, [2, 3]], [['e', 'f'], ['g', 'h']]]

list_b[1][1] = 4
print(list_b) # >>[[1, [2, 3]], [['e', 'f'], 4]]

1.3 スライスによるリストの参照

リストの要素を参照する方法には「スライス」というPythonが持つ機能を利用する方法があります。先に紹介した個別インデックス指定よりも「スライス」を使うことで効率的に要素を参照することができるようになります

具体的な書き方としては、抽出したい要素の範囲を開始位置と終了位置を「:」で挟んで範囲指定するといったものです。また、抽出要素の範囲指定のステップ(増分量)をオプションで指定することができます。スライスの書式は次のとおりとなります。

スライスによるリストの参照

スライスにはステップ指定の有無により2つの書式があります

➀はステップさせない場合、➁はさせる場合です

➀リスト名[開始位置終了位置]

➁リスト名[開始位置終了位置ステップ]


引数1:開始位置: 開始位置のインデックス(省略可能)

引数2:終了位置: 終了位置のインデックス(省略可能)

引数3:ステップ: 範囲内のステップ数(増分値)の指定(省略可能)

※引数1~3はいずれも省略可能

戻り値:抽出した新たなリスト

スライスの概要
図4 スライスの概略図

例1.スライスのインデックス指定を前方基準にして参照した例となります。開始位置を省略([:終了位置])すると先頭の要素から参照、終了位置を省略([開始位置:])すると末尾の要素まで、両方省略した場合([:])は全要素を参照することになります。

# スライスによるリストの参照(インデックスの前方基準)

words = ["blue", "red", "green", "yellow", "pink", "black", "white"] # 元のリスト
#-------------------------------------------------------------------------------------

# ➀開始・終了位置を省略した場合は、「要素全てを抽出」
print(words[:])     # >>['blue', 'red', 'green', 'yellow', 'pink', 'black', 'white']

# ➁終了位置を省略した場合は末尾までが範囲 「インデックス3~末尾迄の要素」
print(words[3:])    # >>['yellow', 'pink', 'black', 'white']

# ➂開始位置を省略した場合は先頭からが反に 「先頭~インデックス3の要素」
print(words[:3])    # >>['blue', 'red', 'green']

# ➃インデックス3~5の間の要素
print(words[3:5])    # >>['yellow', 'pink']

#-------------------------------------------------------------------------------------

# 元のリストはそのまま変更されることはない
print(words)         # >>['blue', 'red', 'green', 'yellow', 'pink', 'black', 'white']

例2.次はスライスのインデックス指定を後方基準にして参照した例となります。末尾の要素を「-1」を基準にして範囲を指定します。

# スライスによるリストの参照(インデックスの後方基準)

words = ["blue", "red", "green", "yellow", "pink", "black", "white"] # 元のリスト
#-------------------------------------------------------------------------------------

# ➀最後の要素
print(words[-1:])               # >>['white']

# ➁最後から2番目~最後の要素
print(words[-2:])               # >>['black', 'white']

# ➂最後から3番目~最後の要素
print(words[-3:-1])             # >>['pink', 'black']

# ➃最後の要素を除く全ての要素
print(words[:-1])               # >>['blue', 'red', 'green', 'yellow', 'pink', 'black']

例3.次はステップ数を指定した場合の例です。例1,2のように抽出範囲を決めてから、その次にその範囲の中から何個飛ばし(ステップ幅)で参照するのかを指定します。ステップ数に「2」を指定すると1個飛ばしとなりますが、「1」を指定するとステップを省略したのと同じ扱いになります。

# スライスによるリストの参照(ステップを指定した場合)

letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j" ] # 元のリスト
#-------------------------------------------------------------------------------------

# ➀先頭から末尾まで1個飛ばしの要素を抽出
print(letters[::2])        # >>['a', 'c', 'e', 'g', 'i']

# ➁2番目の要素から末尾まで1個飛ばしの要素を抽出
print(letters[1::2])        # >>['b', 'd', 'f', 'h', 'j']

# ➂2番目の要素から8番目の要素まで1個飛ばしの要素を抽出
print(letters[1:7:2])        # >>['b', 'd', 'f']

#-------------------------------------------------------------------------------------

# ステップ数に1を指定すると、stepを省略した結果と変わらない
print(letters[::1])         # >>['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']

2. リストの連結と比較

Python_基本文法_内包表記

リストどうしを連結して新たなリストを作成する方法とリストオブジェクトの比較結果について解説します。

2.1 +演算子でリストを連結する

複数のリストを連結させるには+演算子を使います、使用例は次のとおりです。2個3個…と制限なく連結させることができます。また、通常の数値演算子のように代入演算子+=を使うこともできます。

但し、-や*演算子などはリスト同士の演算では使えません。

# +演算子, +=代入演算子を使ったリストの連結

#--------------------------------------------------------
# +演算子によるリストの連結

list_a = ['a','b','c']
list_a = list_list + [1, 2, 3]   # +演算子でリストを連結(後置)
print(list_a) # >>['a', 'b', 'c', 1, 2, 3]

list_a = [4, 5, 6] + list_a   # +演算子でリストを連結(前置)
print(list_a) # >>[4, 5, 6, 'a', 'b', 'c', 1, 2, 3, 1, 2, 3]

list_b = [1, 2] + ['a', 'b'] + [3, 4] + ['c', 'd']   # 連結できるリスト数に制限はない
print(list_b) # >>[1, 2, 'a', 'b', 3, 4, 'c', 'd']

#--------------------------------------------------------
# +=代入演算子によるリストの連結

list_c = []
list_c += ['abc']             # += 代入演算子によるリストの連結
list_c += ['efg', 1, 2, 3]    
print(list_c) # >>['abc', 'efg', 1, 2, 3]

2.2 extendメソッドとappend関数の違い

また、別の方法としてリストオブジェクトに用意されているextend()メソッドを使うというのもあります。引数に追加したいリスト(イテラブルなオブジェクト)を指定します。使用例は次のとおりです。

# extend()メソッドを使ったリストの連結

data_1 = [1, 2, 3]
data_2 = ['a', 'b', 'c']

data_1.extend(data_2)    # >>extend()メソッドの実行(data_1にdata_2を連結)
print(data_1)            # >>[1, 2, 3, 'a', 'b', 'c']

data_1 = [1, 2, 3] # 元リストの初期化

data_2.extend(data_1)    # >>extend()メソッドの実行(data_2にdata_1を連結)
print(data_2)            # >>['a', 'b', 'c', 1, 2, 3]

#------------------------------------------------------------------
# append()メソッドとの違いについいて

data_1 = [1, 2, 3]
data_2 = ['a', 'b', 'c']

data_1.append(data_2)    # append()メソッドの実行(data_1にdata_2を追加)
print(data_1)            # >>[1, 2, 3, ['a', 'b', 'c']]

似たような機能を提供するメソッドにappend()メソッドがありますが、連結する単位が異なりますので注意してください。概略図は以下のとおりで、append()メソッドはオブジェクト丸ごと追加するイメージとなります。

extend関数とappend関数の違い
図5 extend()とappend()メソッドの違い

append()メソッドについてはこちら

2.3 リストオブジェクトの比較

リストオブジェクトの比較(メモリアドレス上の関係)について解説します、例として次のように全く同じ要素をもつ2つのリスト(list_aとlist_b)があったとします。この2つを比較演算子「==」で評価すると当然ですが同じ(True)という結果が戻ります。(1)

今度はオブジェクトとして比較してみます、オブジェクトの比較には演算子「is」を使います。今度は2つは別オブジェクトであることを示す(False)が結果として戻りました。(2)

# リストオブジェクトの比較

# 値(要素)が全く同じリストオブジェクトを定義
list_a = ['a', 'b', 'c']
list_b = ['a', 'b', 'c']

#(1)
# 値の比較する演算子「==」ではTrueとなり等しいと判定
print(list_a == list_b) # >>True

#(2)
# オブジェクトを比較する演算子 「is」ではFalseとなり等しくない
print(list_a is list_b) # >>False

# オブジェクトのIDは不一致である
print(id(list_a)) # 2248836469000
print(id(list_b)) # 2248837134088

#別オブジェクトであることを確かめる
list_a.append('d') # list_aの要素に変更を加える

print(list_a) # >>['a', 'b', 'c', 'd']
print(list_b) # >>['a', 'b', 'c'] # list_bにはlist_aの変更は反映されない

この関係を図示すると次のようになります。list_a, list_bは値は同じだがメモリ空間上は全くことなる別オブジェクトということになります。

リストオブジェクトの比較イメージ(1)
図6 オブジェクトのメモリ空間上の関係➀

list_a, list_b両者が同じオブジェクトを指すようにするには「list_b = list_a」といったように参照先を同じにする必要があります。今度は値もオブジェクトも同じだということが確かめられました。(1)(2)

ただし、オブジェクトが同じということは片方の要素を変更した場合は、同じ参照先を指していいるもう片方のリストの内容も変更されてしまいます。(3)

したがって、オブジェクトを共有する場合はこの点を気を付けて使う必要があります。

# リストオブジェクトの比較

# 値(要素)が全く同じリストオブジェクトを定義
list_a = ['a', 'b', 'c']

list_b = list_a # list_aの参照先をList_bと共有する

#(1)
# 値の比較する演算子「==」ではTrueとなり等しいと判定
print(list_a == list_b) # >>True

#(2)
# オブジェクトを比較する演算子 「is」ではTrueとなり等しいと判定
print(list_a is list_b) # >>True

# オブジェクトのIDは一致する
print(id(list_a)) # 2248838681480
print(id(list_b)) # 2248838681480

#(3)
#別オブジェクトであることを確かめる
list_a.append('d') # list_aの要素に変更を加える

print(list_a) # >>['a', 'b', 'c', 'd']
print(list_b) # >>['a', 'b', 'c', 'd'] ※list_bにもlist_aの変更が反映される

この関係を図示すると次のようになります。

リストオブジェクトの比較イメージ(2)
図7オブジェクトのメモリ空間上の関係②

3. まとめ

いかがでしたでしょうか?

今回は、リストの具体的な使い方として参照と更新、連結・比較について解説してきました。ポイントをまとめると次のようになります。

➀リストを参照更新するには、インデックスを個別要素を指定する場合と、スライスで範囲指定する場合があり用途に応じて使い分ける。

➁リストを連結させるには+演算子extendメソッドを使う方法がある。

➂同一の値・要素をもったリストでも同じオブジェクトを指しているのではない。同一オブジェクトとするにはオブジェクト変数を共有する必要がある。

繰り返しとなりますが、リストはPythonのデータ構造の中で最も使用頻度が高く、使いこなす必要があります。参考記事「リストの生成と関連メソッド」と合わせてよく理解されると良いかと思います。

今回の記事を是非、お役立てくださいますと幸いです。

最後までお読みいただきありがとうございました。

タイトルとURLをコピーしました