Python♪リストの基本的な扱い方。リストとNumPy配列との違い。

ゆうちゃんとの勉強もついにリストを勉強することになりました。if文、for文、リスト(配列)が分かれば、できることがぐっと広がるので楽しみです。

でも、リストについてどこまで教えればよいのか悩むところです。リストと配列の違い、 NumPy配列 、スライス、内包表記、浅いコピーと深いコピーなど、知っておいて欲しいことはたくさんあります。どういう順番で説明すればよいのか悩んでしまいます。

わたし「今日から勉強するリストって、色々なデータを1つの箱に詰め込んじゃう方法なんだけど、なにが便利かわかる?」
ゆうちゃん「う~ん。アイス食べながら考えようよ。」
わたし「まあ、いきなり、なにが便利かわかるといわれても難しいよね。そうしようか。」
ゆうちゃん「データを整理して見やすくするのかな?わからないけど。」
わたし「ごめん、質問がわかりにくすぎるよね。実はどこまで説明すればいいのか悩んでるのよ。」
ゆうちゃん「いつも、自信満々で教えてるのに、めずらしいね。難しいと思ったらすぐに言うから、どこまでも行っちゃってよ。」
わたし「・・・そうね、リストが難しいわけではないんだけど、教える順番で悩んじゃって。」
ゆうちゃん「Pythonのせ・ん・せ・い。信頼してるから、とにかく、やっちゃって。」

あらら、そういえば「習うより慣れろ」ってことわざがあったわね。ゆうちゃんからご指導いただいちゃいました。ありがと。

0.ゆうちゃんとPythonシリーズ

この記事は「ゆうちゃんとPythonシリーズ」の記事です。一連の記事は、以下のリンク集を参照してください。

中学生のゆうちゃんとPythonシリーズ

なお、それぞれの記事は、シリーズの中でそれまでに習った文法を使ってサンプルコードを考えています。実際には、もっと、効率のよい書き方があるかもしれませんが、ご了承ください。

1.リストの概要

リストは、複数のデータを1つのグループにまとめて整理する仕組みです。なお、まとめられたデータを要素と呼び、それぞれの要素に通し番号がつけられます。

1つにまとめることで、まとめられた中で最も大きい値を求めたり、大きい順に並べ直したりといったことができるようになるので非常に便利です。また、通し番号をつけることにより、for文を組み合わせて様々なデータの操作が可能となります。

(1) リストの具体例

さて、 言葉だけでは分からないと思いますので、 具体的な例で考えてみましょう。あるクラスに「ゆうちゃん」「のび太」「お地蔵様」の三人の少年がいたとします。これをboysという名前のリストにまとめたいと思います。

リストは、コード01の2行目の右辺(うへん)のように、角括弧(かくかっこ)とコンマを使って表現します。それを変数boysに代入するとboysという名前のリストの完成です。boysをprint文で出力すると、出力02のようにリストがそのまま出力されます。

#コード01
boys = ['ゆうちゃん', 'のび太', 'お地蔵様']
print(boys)
#出力01
['ゆうちゃん', 'のび太', 'お地蔵様']

このとき、各要素には自動的に左から「ゆうちゃん」には0番、「のび太」には1番、「お地蔵様」には2番の番号が付けられます。

各要素につけられた番号は、データを呼び出したり、変更したりするときに使われる番号です。boys[0]、boys[1]、boys[2]のような表記で各要素を指定できます。コード02では3~5行目で各要素を出力しています。また、7行目のように別のデータを代入すれば要素を変更することもできます。

#コード02
boys = ['ゆうちゃん', 'のび太', 'お地蔵様']
print(boys[0])    #「ゆうちゃん」が出力される
print(boys[1])    #「のび太」が出力される
print(boys[2])    #「お地蔵様」が出力される
print(boys)    #boysの中身が全て出力される
boys[1] = '桃太郎'    #1番目の箱に「桃太郎」を代入
print(boys)    #「のび太」が「桃太郎」に変更される
#出力02
ゆうちゃん
のび太
お地蔵様
['ゆうちゃん', 'のび太', 'お地蔵様']
['ゆうちゃん', '桃太郎', 'お地蔵様']

(2) リストのイメージ

では、このリストのイメージを図にしたいと思います。下図では、変数boysに0~2番までの箱が用意されており、それぞれの箱に、「ゆうちゃん」「のびた」「お地蔵様」というデータが入っています。「わざわざ、図にしなくても・・・」と思うかもしれませんが、「配列」という考え方を理解するためにはこの図が必要ですので、しっかりと目に焼き付けてください。

上図は箱を横に並べましたが、箱を縦に並べて0~2の番号を上からつけると下の図のようになります。上の図の方がイメージしやすいですが、下の図も覚えておいてください。

(3) リストには色々な型のデータが入れられる

リストには、’ゆうちゃん’, ‘のび太’, ‘お地蔵様’のようなstr型だけではなく、整数型、不動点小数点型、さらにはリストの中にリストを入れることができるなど、様々なデータ型を混在させることができます。リストはこの様に要素の構成の自由度が高いという特徴があります。

コード03のリストは1つ目の要素’ゆうちゃん’はstr型、2番目の要素100は整数型、3番目の要素[‘円周率’, 3.14]はリストです。このように色々な型を混在できます。

#コード03
x = ['ゆうちゃん', 100, ['円周率', 3.14]]
print(x)
#出力03
['ゆうちゃん', 100, ['円周率', 3.14]]

(4) ちょっとだけNumPy配列

「リスト」に似たものに「配列」がありますが、「配列」は主に技術科学計算など計算速度を重視する場合に使われます。Pythonでは外部ライブラリNumPyで「NumPy配列」と呼ばれるものなどがそれに相当します。「配列」は計算速度は速いですが、違う型の混在を許さないなどリストと比較して色々な制限があります。

NumPyは、Pythonを使いこなしたいと思ったら、必ず覚えることになる外部ライブラリーですので、少しだけ使い方を紹介したいと思います。

コード04を見てください。リストと違うのは2行目でnumpyを読み込む部分と、変数boysに代入する3行目の「np.array()」の部分だけです。リストのコード02とほとんど同じですね。

#コード04
import numpy as np
boys = np.array(['ゆうちゃん', 'のび太', 'お地蔵様'])
print(boys[0])
print(boys[1])
print(boys[2])
print(boys)
boys[1] = '桃太郎'
print(boys)
#出力04
ゆうちゃん
のび太
お地蔵様
['ゆうちゃん' 'のび太' 'お地蔵様']
['ゆうちゃん' '桃太郎' 'お地蔵様']

このように、要素の構成の自由度や追加や削除といった扱いやすさを重視した「リスト」と、計算速度を重視した「配列」は、使用用途の方向性が違うので使用できる関数が違ったり、違うところもありますが、同じようなデータの扱い方ができます。

2.リストの中に同じ長さのリストを入れる

さて、リストの中にリストを入れた例はコード03で既に紹介しましたが、 リストの中のリストの長さをそろえて、リストを配列のように使う例を紹介したいと思います。

(1) 基本的な操作方法

コード05では、boysの1番目の要素は[‘ゆうちゃん’, 92]、2番目の要素は[‘のび太’, 33]、3番目の要素は[‘お地蔵様’, 56]です。それぞれ、名前と数学のテスト結果を要素に持つリストです。4~6行目では、それぞれ、この0~3番目の要素を出力しています。また、7行目では2番目の要素の内容を変更しています。

#コード05
boys = [['ゆうちゃん', 92], ['のび太', 33], ['お地蔵様', 56]]
print('boys[0] =', boys[0])
print('boys[1] =', boys[1])
print('boys[2] =', boys[2])
print('boys =', boys)
boys[1] = ['恵比寿様', 42]
print('boys =', boys)
#出力05
boys[0] = ['ゆうちゃん', 92]
boys[1] = ['のび太', 33]
boys[2] = ['お地蔵様', 56]
boys = [['ゆうちゃん', 92], ['のび太', 33], ['お地蔵様', 56]]
boys = [['ゆうちゃん', 92], ['恵比寿様', 42], ['お地蔵様', 56]]

リストの要素の数が増えると、どんどん横に長くなってしまいますので、リストは途中で改行することができ、上記コード05の2行目を下のコード06の2~4行目のように書き換えることができます。そして、出力結果は出力05と全く同じになります。

#コード06
boys = [['ゆうちゃん', 92],
        ['のび太'  , 33],
        ['お地蔵様', 56]]
print('boys[0] =', boys[0])
print('boys[1] =', boys[1])
print('boys[2] =', boys[2])
print('boys =', boys)
boys[1] = ['恵比寿様', 42]
print('boys =', boys)

次にリストboysの名前だけ、あるいは点数だけを操作してみましょう。コード07では、5~10行目で各要素を出力しています。例えばboys[0][1]は、0番目の少年である’ゆうちゃん’の1番目のデータである算数の得点なので92が出力されます。

また、12行目では、boys[1][0]の要素を’桃太郎’に変更しています。

#コード07
boys = [['ゆうちゃん', 92],
       ['のび太'  , 33],
       ['お地蔵様', 56]]
print('boys[0][0] =', boys[0][0])
print('boys[0][1] =', boys[0][1])
print('boys[1][0] =', boys[1][0])
print('boys[1][1] =', boys[1][1])
print('boys[2][0] =', boys[2][0])
print('boys[2][1] =', boys[2][1])
print('boys =', boys)
boys[1][0]='桃太郎'
print('boys =', boys)
#出力07
boys[0][0] = ゆうちゃん
boys[0][1] = 92
boys[1][0] = のび太
boys[1][1] = 33
boys[2][0] = お地蔵様
boys[2][1] = 56
boys = [['ゆうちゃん', 92], ['のび太', 33], ['お地蔵様', 56]]
boys = [['ゆうちゃん', 92], ['桃太郎', 33], ['お地蔵様', 56]]

(2) 行列計算

これを図にすると以下のようになります。箱を縦横に並べて、靴箱のようになっています。靴箱の縦方向を「行」と呼び、靴箱の横方向を「列」といいます。そして、例えば boys[1][0] の’のび太’は「1行目0列目の要素」と表現します。

また、呼び出す場合のboys[1][0]では、左側の数字1が「行数(ぎょうすう)」を示し、右側の数字が「列数(れつすう)」を示します。

boys[行][列]

実は「行」や「列」といった特別な名前がついているのは靴箱の形の場合だけです。 この靴箱の形は非常に大切な形で、数学では「行列(ぎょうれつ)」「 matrix (マトリクス)」と呼ばれます。「行列」を使った計算は、「線形代数(せんけいだいすう)」と呼ばれる数学の分野の1つであり、 行列の計算の考え方がなければ、コンピューターを使った科学技術計算はこれほど進化していなかったのではないでしょうか。機械部品の解析や、人工知能も「行列計算」が計算の中心です。

とにかく、「行列」の形が非常に重要であることを理解しましょう。そして、行列の図は何度も見て覚えましょう。

行列計算(行列を使った計算)は、プログラムでは「配列」「array(アレイ)」を使って計算します。Pythonでは、NumPy配列が有名です。リストと配列は異なりますが、リストでもここで紹介したようにすることで配列と同じように使うことができます。

なお、靴箱のような形の配列は2次元配列といいます。一方、最初に説明した下図のような配列は1次元配列といいます。

(3) NumPy配列は整形でなければならない

リストでは、次のように内側のリストの長さがそろってなくてもかまいません。一方、NumPy配列はきれいな長方形でなくてはならないので注意しましょう。

#コード08
boys = [['ゆうちゃん', 92], 'のび太', ['お地蔵様', 56]]
print('boys[0][0] =', boys[0][0])
print('boys[0][1] =', boys[0][1])
print('boys[1] =', boys[1])
print('boys[2][0] =', boys[2][0])
print('boys[2][1] =', boys[2][1])
print('boys =', boys)
#出力08
boys[0][0] = ゆうちゃん
boys[0][1] = 92
boys[1] = のび太
boys[2][0] = お地蔵様
boys[2][1] = 56
boys = [['ゆうちゃん', 92], 'のび太', ['お地蔵様', 56]]

3.3次元配列

リストで3次元配列(厳密には配列ではありませんが)を作ってみましょう。コード09のリストではA組の「ゆうちゃん」「のび太」「お地蔵様」だけではなくB組の「悪魔」「死神」「貧乏神」もデータに加えました。例えばboys[1][2][0]では、左側の[1]はB組であることを示し、真ん中の[2]は0から始まり2番目の少年であることを示し、右側の[0]は、点数ではなく名前を指していることを示します。

#コード09
boys = [[['ゆうちゃん', 92], ['のび太', 33], ['お地蔵様', 56]],
        [['悪魔'     , 26], ['死神'  , 92], ['貧乏神'  , 88]]]
print('boys =', boys)
print('boys[0] =',boys[0])
print('boys[1] =',boys[1])
print('boys[0][0] =',boys[0][0])
print('boys[0][1] =',boys[0][1])
print('boys[0][2] =',boys[0][2])
print('boys[1][0] =',boys[1][0])
print('boys[1][1] =',boys[1][1])
print('boys[1][2] =',boys[1][2])
print('boys[0][0][0] =',boys[0][0][0])
print('boys[0][0][1] =',boys[0][0][1])
print('boys[0][1][0] =',boys[0][1][0])
print('boys[0][1][1] =',boys[0][1][1])
print('boys[0][2][0] =',boys[0][2][0])
print('boys[0][2][1] =',boys[0][2][1])
print('boys[1][0][0] =',boys[1][0][0])
print('boys[1][0][1] =',boys[1][0][1])
print('boys[1][1][0] =',boys[1][1][0])
print('boys[1][1][1] =',boys[1][1][1])
print('boys[1][2][0] =',boys[1][2][0])
print('boys[1][2][1] =',boys[1][2][1])
#出力09
boys = [[['ゆうちゃん', 92], ['のび太', 33], ['お地蔵様', 56]], [['悪魔', 26], ['死神', 92], ['貧乏神', 88]]]
boys[0] = [['ゆうちゃん', 92], ['のび太', 33], ['お地蔵様', 56]]
boys[1] = [['悪魔', 26], ['死神', 92], ['貧乏神', 88]]
boys[0][0] = ['ゆうちゃん', 92]
boys[0][1] = ['のび太', 33]
boys[0][2] = ['お地蔵様', 56]
boys[1][0] = ['悪魔', 26]
boys[1][1] = ['死神', 92]
boys[1][2] = ['貧乏神', 88]
boys[0][0][0] = ゆうちゃん
boys[0][0][1] = 92
boys[0][1][0] = のび太
boys[0][1][1] = 33
boys[0][2][0] = お地蔵様
boys[0][2][1] = 56
boys[1][0][0] = 悪魔
boys[1][0][1] = 26
boys[1][1][0] = 死神
boys[1][1][1] = 92
boys[1][2][0] = 貧乏神
boys[1][2][1] = 88

3次元配列は下図のような同じ形の2次元配列を重ねたものです。

重ねたあとの図は下図のようになり、立方体になります。なお、4次元以上の配列のコードを記述することも可能ですが、図に表すことはできなくなってしまいます。

boys[①][②][③]

4.リストとNumPy配列の違いのまとめ

リストの概要について説明しましたが、配列との違いについても簡単に説明してきました。ここでは、リストと配列の違いを簡単に説明したいと思います。

  • 「リスト」は、要素の構成の自由度や追加や削除といった扱いやすさを重視しています。一方、「配列」は計算速度を重視しており、行列計算など科学技術計算を行うための関数が多く用意されています。
  • NumPy配列は違うデータの型を混在できません。
  • リストはコード08のようにリストの中に長さの違うリストを混在させることができますが、 NumPy 配列ではできません。
  • この記事では説明しませんでしたが、リストはコードの途中でデータを付け加えたり削除したり、要素の総数を変更することができますが、NumPy 配列では原則として最初に決めたデータの総数を変更しません。

私は、これから先、ゆうちゃんに配列を扱うようなプログラミングに挑戦して欲しいと思っています。そして、それはすぐ後のことかもしれないけれど、私とゆうちゃんの勉強会が終わったあとのことかもしれません。だから、配列を扱う入り口の所までは立たせてあげたい!

ゆうちゃんが自分でNumPy配列を勉強をしたり、別の言語の配列を勉強したりするときに、今日の勉強が役にたって欲しいと思っています。

勉強会の最初に迷っていたのは、プログラミング初心者のゆうちゃんにリストと配列の違いをどの程度まで説明するかについてです。ゆうちゃんは「分かった!完璧!教えるのうまいね♪こんなことで悩むなんて、ありがとう。」と言ってくれましたが、欲張りすぎて混乱しなかったかしら?

5.例題

コード10では、リストboysに、ゆうちゃん、のび太、お地蔵様のテスト結果を入力しましたが、 7行目に1行記述して、 のび太くんの点数を100点に変更してください。なお、出力結果は出力10のようになります。

#コード10
boys = [['ゆうちゃん', 92],
        ['のび太'  , 33],
        ['お地蔵様', 56]]
print('<今回のテスト結果>')
print(boys)
■ここにコードを記述しましょう■
print('<のび太君の願望>')
print(boys)
#出力10
<今回のテスト結果>
[['ゆうちゃん', 92], ['のび太', 33], ['お地蔵様', 56]]
<のび太君の願望>
[['ゆうちゃん', 92], ['のび太', 100], ['お地蔵様', 56]]
解答の表示・非表示の切り替え

※ブラウザによっては最初から表示されてしまいます。(Google Chrome推奨)

以下、7行目でのび太君の点数を書き換えました。

#コード10の解答
boys = [['ゆうちゃん', 92],
        ['のび太'  , 33],
        ['お地蔵様', 56]]
print('<今回のテスト結果>')
print(boys)
boys[1][1] = 100
print('<のび太君の願望>')
print(boys)

私が実際に購入した教材のご紹介

以下、私が実際に購入したPythonの教材をまとめてみました。 Pythonを学習する上で、少しでもお役に立つことができればうれしいです。

Python♪私が購入したPythonの書籍のレビュー

UdemyのPythonの動画講座を書籍を買う感覚で購入してみた