独学でPython『リスト操作』の基本を学ぶ【プログラミング基礎練習問題2】
(Pythonの基本を初めからしっかり学びたい方はこちら↓↓)
プログラミングの基本文法を学んだ方からよくこのような質問を頂きます。
悩むペン銀
Pythonの基本構文を学んで、プログラミングに対する基礎知識もある程度勉強したんだけど、次に何をすればいいのか分からない。次に何をすればより成長できるか教えて欲しい
こう言った『次に何すればいいか分からない』と言う疑問に対し
僕からの回答を言うと、
『沢山問題を解きましょう』
です。
これこそプログラミング力を飛躍的に向上させる一番の近道です。
このシリーズを最後まで学習することで、これまで学んできた基礎知識を定着させ、
最終的に様々な問題を、Pythonを駆使して解決できるようになるはずです。
本シリーズを習得した後、
得ることができる主な知識・内容は以下3点です。
本記事の内容
この記事を書いている僕は国立大学にてCSの学位を保有しており
エンジニアとしての仕事では現実問題を解き続けています。
実際に問題を解いていくと今まで知らなかった便利な組み込み関数や
新しい思考プロセスを学ぶことができます。
それではやっていきましょう。
目次
(注) 問題のレベルについて
以下に示す問題のレベルは五段階に分割しています。
あくまでも目安なので、自分が解いてみたい・解ける問題から手をつけてみてください。
解けない問題は無理して解いて理解しようとせず、もう少し学びを深めてから取り組みましょう。意外と時間を置いて取り組むと、あっさり解けたりします。
プログラミングの勉強は継続が重要です。なので楽しさを優先しましょう!
【問題1】リスト操作 レベル: difficult
地雷の場所を特定せよ
引数として"="
と"*"
が要素として格納されたリストが与えられる。"*"
は地雷の場所を示していて、"="
は地雷が無い地点だ。この時、地雷を囲う場所(縦・横・斜め)に1を、そのほかの地雷が無い場所には0を加算して表示して欲しい。戻り値はリスト型であり、関数名はcreateBombBoardとしよう。
具体例
createBombBoard関数に引数を渡した場合
以下のような結果となります。
注意事項
以下、実装における注意事項です。
テスト
以下のテストコードをエラー無く通過できれば正解です。
作成した関数を以下のように自分の環境に書き込んで完成させ
Runボタンを押して確認してみましょう。
# This will get executed each time the exercise gets initialized
def createBombBoard(arg):
ここにコードを入力してください
return your_answer
data = [
["*", "=", "=", "=", "*"],
["=", "=", "=", "=", "="],
["*", "=", "=", "=", "="],
["=", "=", "=", "*", "="],
["=", "=", "*", "=", "="]
]
assert createBombBoard(data) == [[0, 1, 0, 1, 0],
[2, 2, 0, 1, 1],
[0, 1, 1, 1, 1],
[1, 2, 2, 1, 1],
[0, 1, 1, 2, 1]]
data = [
["=", "=", "=", "*", "="],
["=", "*", "=", "=", "="],
["=", "=", "=", "=", "="],
["=", "=", "=", "*", "="],
["*", "*", "=", "=", "="]
]
assert createBombBoard(data) == [[1, 1, 2, 0, 1],
[1, 0, 2, 1, 1],
[1, 1, 2, 1, 1],
[2, 2, 2, 0, 1],
[1, 1, 2, 1, 1]]
print('Pass!!')
<-
) to create the variable a
.解答例
def createBombBoard(arg):
import numpy as np
result = np.zeros(np.array(arg).shape, dtype=np.int8)
for idx_row, row in enumerate(arg):
for idx_col, col in enumerate(row):
if col == '*':
data = [[idx_row-1, idx_col-1], [idx_row-1, idx_col], [idx_row-1, idx_col+1], [idx_row,idx_col-1], [idx_row, idx_col+1], [idx_row+1, idx_col-1], [idx_row+1, idx_col], [idx_row+1, idx_col+1]]
for l in data:
try:
if l[0] < 0 or l[1] < 0:
continue
result[l[0], l[1]]+=1
except IndexError:
continue
elif col == '=':
continue
return result.tolist()
解説付き解答例
def createBombBoard(arg):
import numpy as np # python数値計算ライブラリnumpyのimport
# np.zeros関数は0で初期化されたndarrayを生成する。
# 生成するサイズは引数で与えられたlistと同じ次元のものを取得する為
# np.array(arg).shapeでサイズを取得して引数に与えている
result = np.zeros(np.array(arg).shape, dtype=np.int8)
# 引数で与えられたリストの行毎の要素にアクセス
for idx_row, row in enumerate(arg):
# リストの列毎の要素にアクセス
for idx_col, col in enumerate(row):
# リストにおける爆弾の場所を特定し、その全方位の場所も特定する
if col == '*':
data = [[idx_row-1, idx_col-1], [idx_row-1, idx_col], [idx_row-1, idx_col+1], [idx_row,idx_col-1], [idx_row, idx_col+1], [idx_row+1, idx_col-1], [idx_row+1, idx_col], [idx_row+1, idx_col+1]]
for l in data:
try:
if l[0] < 0 or l[1] < 0:
continue
# 地雷の全方位のマスをインクリメントする
result[l[0], l[1]]+=1
except IndexError:
continue
# 爆弾以外の場所は無視する
elif col == '=':
continue
# np.arrayで操作してきた為、リスト型に変換し、値を返す
return result.tolist()
更に深く学ぶ+α
配列とリストは性質が違う
Pythonでは、(一般的に他の言語でも)配列とリストの性質は異なります。 配列とリストの違いは何か。それはデータ構造にあります。 例えば数値データを効率的に処理するためのモジュールとして、Pythonには外部ライブラリnumpyのndarrayや組み込みモジュールのarrayが用意されています。 これらのデータ構造では 隣り合う要素がメモリ上で連動している 同じ型の変数しか格納できない等の特徴があります。 一方でリストではメモリ上で数値が連続して格納されることは保証されていませんが、様々な型のオブジェクトを保持することができます。
enumerate関数について
enumerate
関数は要素のインデックスと要素を同時に取り出したい時に役に立つ関数です。たとえば以下のようにして活用できます。
for idx, element enumerate(["太郎", "次郎", "三郎"]):
print(idx, element)
0, "太郎"
1, "次郎"
2, "三郎"
このように、enumerateを使うことで引数で与えられたリストの要素が
1つずつ取り出されると同時にそのインデックスが0から順に取得できます。
【問題2】リスト操作 レベル: easy
リスト内要素の順番を調査せよ
引数として整数型の数字を格納した2つのリストを受け取る。これらをマージし、1つのリストにして要素を昇順(0,1,2,3,4...)に並び替えよう。この時、値が飛ぶことなく順番通りの要素が格納されている場合はTrue
を。そうでない場合はFalse
を返すcheckOder関数を実装せよ。
具体例
実装したcheckOder関数に引数を与えた時、
結果は以下のようになります。
checkOder([2,3,1,4],[5,8,6,7])→True
checkOder([3,2,4,5],[9,6,10,1])→False
checkOder([4,9,2,1,8],[13,12,11,10,3])→False
注意事項
以下の要件にしたがって関数を設計してください
テスト
以下のテストコードをエラー無く通過できれば正解です。
あなたの回答を書き込んで関数を完成させ、Runボタンを押して確認してみましょう。
# This will get executed each time the exercise gets initialized
def merge_dictionary(dict1,dict2):
#ここにコードを入力してください
return your_answer
arg1 = [2,3,5]
arg2 = [0,1,4]
assert checkOder(arg1, arg2) == True
arg1 = [5,3,2,8]
arg2 = [0,1,4,6,7]
assert checkOder(arg1, arg2) == True
arg1 = [0,9,2,1,4,5]
arg2 = [6,3]
assert checkOder(arg1, arg2) == False
print('Pass!!')
<-
) to create the variable a
.解答例
少なくとも10分間は自分の頭で考えて問題を解きましょう。
10分考えても解法が浮かばない場合は解答例を見て、問題の解き方を学んでください。
def checkOder(arg1,arg2):
tmp_list = arg1
for i in arg2:
tmp_list.append(i)
sorted_list=sorted(result)
result = []
for i, e in zip(sorted_list, range(min(sorted_list),max(sorted_list)+1)):
if i == e:
result.append(0)
else:
result.append(1)
if sum(result) == 0:
return True
else:
return False
解説付き解答例
def checkOder(arg1,arg2):
tmp_list = arg1
for i in arg2:
tmp_list.append(i) # arg1とarg2の要素を1つのリストに統合する
sorted_list=sorted(result) # 統合してできたリストの要素を照準に並び替える
result = []
for i, e in zip(sorted_list, range(min(sorted_list),max(sorted_list)+1)): # 並び替えたリストが要素に欠損なく要素を格納しているか確認する
if i == e:
result.append(0) # 欠損がなければ0
else:
result.append(1) # 欠損があれば1
if sum(result) == 0:
return True
else:
return False