🔙
🔝

二次元リスト

二次元データの取り扱いができるようになります👍

Chatpter.1 - そもそも次元とは?

コンピュータは低次元

  • 「空間を表す単位」とされていますが、コンピュータに空間はありません。

  • コンピュータの世界で指す「次元」の定義は別物と考えてください。

  • コンピュータに存在する次元は、簡単に言うと次のようなものです。

  • 一次元
    0 と 1。デジタル。
    この一桁の単位を「ビット(bit)」と言います。
    一次元は1ビットです。
    プログラムでは、「1つの値」が一次元です。
    0
    123
    '次元大介'

    一次元配列はいれつ (添字が1つ)
    一次元が連なったもの。一次元リストなど。
    [0, 1, 1, 0, 1]
    [1]

    二次元配列 (添字が2つ)
    一次元配列の配列。
    [[0, 1], [1, 0, 1], [1, 0]]
    [[0], [1]]
    [[0]]

    三次元配列 (添字が3つ)
    [[[0, 1], [1, 0]], [[1, 0], [0, 1]]]

    ※ 実質、四次元・・・五次元・・・と続けられなくもないですが、まず使わないと思います。😅
    ※ 「配列」とは、1つ1つの場所が隣接して列になっているものです。リストの要素みたいに。
      ただし厳密には配列(array)とリスト(list)は異なるものです。

  • この 0 か 1 のところを数値や文字列に置き換えたものが、今まで扱ってきたリストの形になります。

  • リアルでは三次元になって初めて「立体」と呼ばれますが、コンピュータは一次元の「粒」も立体と考えてください。

  • この一次元の「粒」の集合体がコンピュータの世界なのです。

  • 黒い粒(0)も白い粒(1)も粒は粒です。

  • スモモもモモもモモはモモです。

  • 箱を並べたり積み重ねたりする感じに似てますね。😺

Chatpter.2 - コンピュータとの付き合い方

脳内とコンピュータをリンクする

  • コンピュータの形と、自分が想像する形を相互変換しなくてはいけません。

  • これが案外、人間として賢い人ほど苦手と感じる作業なんです。

  • 人間(アナログ)←→コンピュータ(デジタル)の変換作業を人間がやらなければならないわけですから、それはもう大変な労力となります。

  • コンピュータはアナログ思考ができません。

  • ならば人間がデジタル思考でコンピュータを理解する一択となります。

  • 今、そのためにプログラムを学んでいるわけです。

  • デジタル思考とは論理思考です。

  • 0 と 1 の考えしかできない相手に自由な思考を求めても無理な話です。

  • コンピュータはマニュアル通りにしか働きません。

  • ならばこちらがバカになって次元を下げ、論理を以ってプログラム言語を通してコンピュータと対話しましょう。🧐

  • 論理は二次元、コンピュータも二次元。

  • 同じ次元にいる者同士でないとわかり合えないのです。

  • もし「うまくイメージできない・・・」と苦悩しても、それは貴方が賢いからかもしれません。👍


  • 私も苦悩しましたのでよくわかります。

    False

Chatpter.3 - 配列の読み方

コツさえ掴めばあとは簡単!

  • 二次元リストの構造を詳しくのぞいてみましょう!

    5行5列の二次元リスト

    nums_list = [
    	['00', '01', '02', '03', '04'],
    	['10', '11', '12', '13', '14'],
    	['20', '21', '22', '23', '24'],
    	['30', '31', '32', '33', '34'],
    	['40', '41', '42', '43', '44']
    ]
    

  • nums_list[y][x]
    y  x 0 1 2 3 4
    0 '00' '01' '02' '03' '04'
    1 '10' '11' '12' '13' '14'
    2 '20' '21' '22' '23' '24'
    3 '30' '31' '32' '33' '34'
    4 '40' '41' '42' '43' '44'

    '01' にアクセスする場合は nums_list[0][1] と書きます。

    '43' にアクセスする場合は nums_list[4][3] と書きます。

  • リスト(行)を選んでから、要素(列)を選ぶ順になります。


  • 数学の座標は(x, y)と書きますが、
    プログラムでは [縦][横] で [y][x] と反対の書き方になります。

  • 数学慣れしている方は間違えやすいので注意してください。

  • 上の表の形をイメージすることはとても重要です。

  • この形はこの先、いろいろな場面で使われます。

  • 二次元リストは「面」になっていますので、中身をprint()で見てみる際も、中をリストごとに改行して面にして出力するとわかりやすくなります。


  • 余談になりますが、三次元リストを平面の画面に立体として映し出すことは当然できません。

  • 三次元リストも面ごとに映し出して読むことになります。

  • その時はこちらの思考を三次元に上げてイメージするしかありません。

  • 「三次元←→二次元」を往来することになりますので、頭がとても疲れます。

  • ここではめんどくさいめんどくさいので、三次元は扱いません。

  • あとはがんばって!👋

Chatpter.4 - 二次元リストの操作

二次元リストの操作

一部の値を書き換える

一部の値を書き換える

  • 添字を使って要素をピンポイントで指定し、あとは値を代入するのみです。

    nums_list = [
    	['00', '01', '02', '03', '04'],
    	['10', '11', '12', '13', '14'],
    	['20', '21', '22', '23', '24'],
    	['30', '31', '32', '33', '34'],
    	['40', '41', '42', '43', '44']
    ]
    
    nums_list[1][2] = '99'	 # ↓要素1 の →要素2 を 99 にする
    print(*nums_list, sep='\n')
    
    ['00', '01', '02', '03', '04']  ['10', '11', '99', '13', '14']← ここの要素2 を 99 にした ['20', '21', '22', '23', '24']  ['30', '31', '32', '33', '34']  ['40', '41', '42', '43', '44'] 
    添字を変えて試してみよう!
  • 最後のprint()で「リストの中身を『面』にして出力」しています。

一部のリストを書き換える

一部のリストを書き換える

  • 一次元の添字を使ってリストを指定し、あとはリスト(要素)を代入するのみです。

    nums_list = [
    	['00', '01', '02', '03', '04'],
    	['10', '11', '12', '13', '14'],
    	['20', '21', '22', '23', '24'],
    	['30', '31', '32', '33', '34'],
    	['40', '41', '42', '43', '44']
    ]
    
    nums_list[2] = ['99', '99', '99', '99', '99']	 # ↓要素2
    print(*nums_list, sep='\n')
    
    ['00', '01', '02', '03', '04']
    ['10', '11', '12', '13', '14']
    ['99', '99', '99', '99', '99']
    ['30', '31', '32', '33', '34']
    ['40', '41', '42', '43', '44']
    添字を変えて試してみよう!
  • リストを上書き代入しているので、コピーの問題を考慮しなくて大丈夫です。


  • 添字がどの部分を指しているのかがわかるようになれば、あとは今まで学んできたやり方がすべて使えます。

リストの値を出力する

リストをアンパックして出力する

  • 確認の時はともかく、リストのままでは見栄えがよくありません。

  • 値のみの出力を求められることがほとんどです。

  • nums_list = [
    	['00', '01', '02', '03', '04'],
    	['10', '11', '12', '13', '14'],
    	['20', '21', '22', '23', '24'],
    	['30', '31', '32', '33', '34'],
    	['40', '41', '42', '43', '44']
    ]
    
    for nums in nums_list:
        print(*nums)
    
    00 01 02 03 04
    10 11 12 13 14
    20 21 22 23 24
    30 31 32 33 34
    40 41 42 43 44

  • 間のスペースが要らない時は、print()の所を、

    print(*nums, sep='')  # 値が数値でもOK
    

    または

    print(''.join(nums))  # 値が全て文字列の時のみOK
    
    0001020304
    1011121314
    2021222324
    3031323334
    4041424344

    と書くと良いでしょう。

    print()に書き足してみよう!

  • もちろん区切り文字を入れることもできます。

    print(*nums, sep=',')  # 値が数値でもOK
    
    print(','.join(nums))  # 値が全て文字列の時のみOK
    
    00,01,02,03,04
    10,11,12,13,14
    20,21,22,23,24
    30,31,32,33,34
    40,41,42,43,44
    print()に書き足してみよう!
転置有用!

二次元リストの行と列を入れ替える

  • 転置とは、行と列を入れ替える作業です。

    nums_list = [
    	['00', '01', '02', '03', '04'],
    	['10', '11', '12', '13', '14'],
    	['20', '21', '22', '23', '24'],
    	['30', '31', '32', '33', '34'],
    	['40', '41', '42', '43', '44']
    ]
    
    transposed_list = list(zip(*nums_list))  # ← ココ
    for nums in transposed_list:
        print(*nums)
    
    00 10 20 30 40
    01 11 21 31 41
    02 12 22 32 42
    03 13 23 33 43
    04 14 24 34 44

    これが行と列を入れ替える『転置』です。

    解説は次の 「行列の右回転」 の中でやります。


  • 『転置』という言葉や意味は忘れても、「簡単に行と列を入れ替えるやり方がある」ことだけでも軽く覚えておいてください。

行列の右回転

二次元リストの面(行列)を右90度回転する。

  • ここからは今まで『面』と呼んでいたのを『行列ぎょうれつ』という言葉に差し替えます。

  • 行列』とは、下のプログラムの nums_list の形状そのものです。

  • 00 01 02 03 04 10 11 12 13 14 20 21 22 23 24 30 31 32 33 34 40 41 42 43 44

    『行』と『列』だから行列です。😸


  • 行列90度時計回りに回転させる作業をします。

    nums_list = [
    	['00', '01', '02', '03', '04'],
    	['10', '11', '12', '13', '14'],
    	['20', '21', '22', '23', '24'],
    	['30', '31', '32', '33', '34'],
    	['40', '41', '42', '43', '44']
    ]
    
    r_rotated_list = list(zip(*nums_list[::-1]))  # ← ココ
    for nums in r_rotated_list:
        print(*nums)
    
    40 30 20 10 00
    41 31 21 11 01
    42 32 22 12 02
    43 33 23 13 03
    44 34 24 14 04

  • あの短い一文で、なぜこんなことができるのでしょうか?🧐❓

    👇 解説します。👇

  • 初めの形。

    list(zip(*nums_list[::-1]))

    r_rotated_list = list(zip(*[
    	['00', '01', '02', '03', '04'], 
    	['10', '11', '12', '13', '14'],	
    	['20', '21', '22', '23', '24'],	
    	['30', '31', '32', '33', '34'],	
    	['40', '41', '42', '43', '44']
    ][::-1]))
    
    [
    ['00', '01', '02', '03', '04'],
    ['10', '11', '12', '13', '14'],
    ['20', '21', '22', '23', '24'],
    ['30', '31', '32', '33', '34'],
    ['40', '41', '42', '43', '44']
    ]
    

  • [::-1] でリストが反転する。

    r_rotated_list = list(zip(*[
    	['40', '41', '42', '43', '44'],
    	['30', '31', '32', '33', '34'],
    	['20', '21', '22', '23', '24'],
    	['10', '11', '12', '13', '14'],
    	['00', '01', '02', '03', '04']
    ]))
    
    [
    ['40', '41', '42', '43', '44'],
    ['30', '31', '32', '33', '34'],
    ['20', '21', '22', '23', '24'],
    ['10', '11', '12', '13', '14'],
    ['00', '01', '02', '03', '04']
    ]
    

  • * でリストをアンパック。

    r_rotated_list = list(zip(
    	['40', '41', '42', '43', '44'],
    	['30', '31', '32', '33', '34'],
    	['20', '21', '22', '23', '24'],
    	['10', '11', '12', '13', '14'],
    	['00', '01', '02', '03', '04']
    ))
    
    ['40', '41', '42', '43', '44'] ← zip() の 引数1
    ['30', '31', '32', '33', '34'] ← zip() の 引数2
    ['20', '21', '22', '23', '24'] ← zip() の 引数3
    ['10', '11', '12', '13', '14'] ← zip() の 引数4
    ['00', '01', '02', '03', '04'] ← zip() の 引数5
    

  • zip()

    (引数1, 引数2, 引数3, 引数4, 引数5), ・・・
    とジップしていく。

    r_rotated_list = list(
    	('40', '30', '20', '10', '00'),
    	('41', '31', '21', '11', '01'),
    	('42', '32', '22', '12', '02'),
    	('43', '33', '23', '13', '03'),
    	('44', '34', '24', '14', '04')
    )
    
    ('40', '30', '20', '10', '00'),
    ('41', '31', '21', '11', '01'),
    ('42', '32', '22', '12', '02'),
    ('43', '33', '23', '13', '03'),
    ('44', '34', '24', '14', '04')
    

    回転成功!


  • このままでは <zip object at 0x1539b1dd4400> なので、list()で見える化する。

    r_rotated_list = [
    	('40', '30', '20', '10', '00'),
    	('41', '31', '21', '11', '01'),
    	('42', '32', '22', '12', '02'),
    	('43', '33', '23', '13', '03'),
    	('44', '34', '24', '14', '04')
    ]
    
    [
    ('40', '30', '20', '10', '00'),
    ('41', '31', '21', '11', '01'),
    ('42', '32', '22', '12', '02'),
    ('43', '33', '23', '13', '03'),
    ('44', '34', '24', '14', '04')
    ]
    

  • これをprint()で出力すると、

    for nums in r_rotated_list:
    	print(*nums)
    
    40 30 20 10 00
    41 31 21 11 01
    42 32 22 12 02
    43 33 23 13 03
    44 34 24 14 04

  • 「確認したり、書き換えたりしないから見えなくてもいいよ」という場合はlist()化は不要です。

    r_rotated_list = zip(*nums_list[::-1])
    

    <zip object at 0x1539b1dd4400>


  • 全てリスト化したいときは、

    r_rotated_list = [[*tpl] for tpl in zip(*nums_list[::-1])]
    print(*r_rotated_list, sep='\n')
    
    ['40', '30', '20', '10', '00']
    ['41', '31', '21', '11', '01']
    ['42', '32', '22', '12', '02']
    ['43', '33', '23', '13', '03']
    ['44', '34', '24', '14', '04']

  • 誰だ、こんなやり方見つけたのは。頭いいね。

線対称

線対称も簡単に

  • 線対称というのは上下反転・左右反転です。

  • 行だけ、列だけをリバースすると線対称になります。

    左右対称 (各リストの値だけ反転)

    nums_list = [
    	['00', '01', '02', '03', '04'],
    	['10', '11', '12', '13', '14'],
    	['20', '21', '22', '23', '24'],
    	['30', '31', '32', '33', '34'],
    	['40', '41', '42', '43', '44']
    ]
    
    mrr_symmetry = [nums[::-1] for nums in nums_list]  # ← ココ
    for nums in mrr_symmetry:
        print(*nums)
    
    04 03 02 01 00
    14 13 12 11 10
    24 23 22 21 20
    34 33 32 31 30
    44 43 42 41 40

  • 上下対称 (各リストの順番だけ反転)

    nums_list = [
    	['00', '01', '02', '03', '04'],
    	['10', '11', '12', '13', '14'],
    	['20', '21', '22', '23', '24'],
    	['30', '31', '32', '33', '34'],
    	['40', '41', '42', '43', '44']
    ]
    
    line_symmetry = nums_list[::-1]  # ← ココ
    for nums in line_symmetry:
        print(*nums)
    
    40 41 42 43 44
    30 31 32 33 34
    20 21 22 23 24
    10 11 12 13 14
    00 01 02 03 04

    上下対称は、さっきの右回転で途中に出てきましたね。

点対称

点対称すらも簡単に

  • 点対称というのは、行列を180度回転させたものです。

  • 行と列を、両方とも1回ずつリバースすると点対称になります。

    点対称

    nums_list = [
    	['00', '01', '02', '03', '04'],
    	['10', '11', '12', '13', '14'],
    	['20', '21', '22', '23', '24'],
    	['30', '31', '32', '33', '34'],
    	['40', '41', '42', '43', '44']
    ]
    
    point_symmetry = [nums[::-1] for nums in nums_list[::-1]]  # ← ココ
    for nums in point_symmetry:
        print(*nums)
    
    44 43 42 41 40
    34 33 32 31 30
    24 23 22 21 20
    14 13 12 11 10
    04 03 02 01 00

    90度右回転を2回繰り返しても同じ結果が得られます。

二次元リストはよく使う 【駄文】

慣れるとほとんど意識すらしなくなる

  • 「二次元リスト」は今までも使い方を少しずつ見てきていましたので、正直こんなに難しい話とは思わなかったという方もいるでしょう。

  • その通り、もう話すこともあまり無いので、哲学的な内容を含めてちょっと語ってみました。

  • 「二次元リスト」からさりげなく数学に繋がって行きましたけど、逆に考えれば数学的なことを知らず知らずのうちにプログラムでやってきているのです。

  • 数学が全然わからなくても例えば、

    i = 1 10 i
    sum(i for i in range(1, 11))
    

    これがプログラムを見ただけで何なのかがもうわかるかと思います。もう言葉で説明するより、プログラムで説明したほうが早いですね。😹

  • この先も学習を続けていくと、数学知識がなくてもプログラムでそれらが自然に身に付いていきます。

  • さんざん使ってきた『関数』というのも数学です。私は数学の関数はよくわかりませんし興味もありません。😽

  • でもプログラムの関数は使えます。

  • 関数は英語で function と書きます。

  • function とは「機能」という意味もあります。キーボードのファンクションキーの function ですね。


  • 「行列」というのも行列ではなく「二次元リスト」と捉えるだけで途端にわかりやすくなると思います。逆も然りです。

  • 二次元リストは競技プログラミングや学習サイトの問題でよく使われます。

  • 問題をこなしているうちに、いつの間にか二次元リストの操作を無意識にやれるようになっています。

  • このレベルに達するのも、実はそんなに時間はかかりません。プログラミングが面白いと感じたら1か月くらい?そんなにかからないかな?


  • ここまで読んで来たということは、それなりにプログラミングの楽しさを感じていることと思われます。

  • 数学がわからないとどうしても越えられない壁というのもありますが、そういうのはあっさり避けて通りましょう。体当たりし続けていても今は時間の無駄でしかありませんから。


  • 数学(数の世界)もコンピュータと同じ「二次元」です。なのでとても相性が良いです。
    ※ 十進数の小数と二進数はあまり相性はよくありませんが。😓

  • 論理は二次元、科学も二次元、言語も二次元。これら二次元は必ず「再現性」を持ちます。

  • 一方、現実(高次元)は「覆水盆に還らず」です。過ぎ去った事象は二度と戻りません。

  • 低次元で考えた結論を高次元にぴったり当てはめようとしても、それは無理な話なのは明白です。机上の空論でしかありません。

  • なので、人間が機械オンチなのはごくふつうのことなんです。劣等感を抱かないでください。

  • 人間には人間の、コンピュータにはコンピュータの得手不得手があります。適材適所、役割分担は大切です。

  • しかし学習は重要です。AIが人間の見るもの聞くもの触れるものを学習して人間を学んでいくように、人間もコンピュータに多く触れて学習していけば、思考が違っても次元を合わせて(歩み寄って)お互いを程よく理解しあえる関係となるでしょう。

  • それは人間同士でも同じことが言えますね。