課題08-1 Stack #
難易度 ⭐
LIFO(Last in, First out; 後入れ先出し)のStack
を表すクラスを実装してください.
push
メソッドにitem
を渡すと,リストの一番最後にitem
を追加します.pop
メソッドを呼び出すと,リストの一番最後の要素を取り出して返します(リストからは最後の要素を削除します). 要素が存在しない場合(リストの長さが0
の場合)はNone
を返します.peek
メソッドは,リストの一番最後の要素を返しますが,リストからは要素を削除しません.len
メソッドは,スタックにある要素数を返します.
なお,コンストラクタの引数でリストを初期化できるようにしてください(デフォルト引数で None
を受け取るようにしてください.理由はこちら).
Stack
クラスの定義の下に以下の Python コードを書いて実行してテストが通るように stack.py
を作成してください.
class Stack:
pass # pass を削除して,以下のテストコードが通るようプログラムを書いてください
s1 = Stack()
s1.push("This")
s1.push("is")
s1.push("stack")
s1.push("test")
assert s1.len() == 4, "スタックの長さは4になっているはずです"
assert s1.peek() == "test", "peek() は最後の要素である test を返すべきです"
assert s1.len() == 4, "peek() は要素の長さを変更しません"
assert s1.pop() == "test", "pop() は最後の要素である test を返すべきです"
assert s1.pop() == "stack", "pop() は最後の要素である stack を返すべきです"
assert s1.pop() == "is", "pop() は最後の要素である is を返すべきです"
assert s1.pop() == "This", "pop() は最後の要素である This を返すべきです"
assert s1.len() == 0, "スタックの長さは0になっているはずです"
s2 = Stack([1, 2, 3, 4, 5]) # コンストラクタで要素を指定できる.
assert s2.len() == 5, "スタックの長さは5になっているはずです"
s2.pop()
s2.pop()
s2.pop()
s2.pop()
s2.pop()
assert s2.len() == 0, "スタックの長さは0になっているはずです"
s3 = Stack()
assert s3.pop() == None, "空のスタックから pop() すると None が返るべきです"
課題08-2 環状バッファ #
難易度 ⭐⭐
n
個の要素を持つ環状バッファを表すRingBuffer
クラスを実装してください.
環状バッファとは,n
個の要素を持つリング状のバッファです.
要素を追加したときn
を超えると,最初に追加した要素が上書きされる構造です.
コンストラクタで n
を受け取ってください.ただし,n
が指定されない場合は 12
が指定されたものとしてください.
RingBuffer
クラスの定義の下に以下の Python コードを書き,実行するとエラーなく実行できるようにしてください.
ring_buffer.py
というファイル名で保存してください.
RingBuffer
クラスが持つべきメソッドは以下のテストコードを参照の上,考えてみてください.
class RingBuffer:
pass # pass を削除して,以下のテストコードが通るようプログラムを書いてください
rb1 = RingBuffer(3)
assert rb1.get(0) == None, "何も要素が入っていないため,None であるはずです"
rb1.add(1)
assert rb1.get(0) == 1, "0番目の要素は 1 であるはずです"
rb1.add(2)
rb1.add(3)
rb1.add(4) # 最初の要素である 1 が上書きされる.
assert rb1.get(0) == 4, "0番目の要素は 4 であるはずです"
assert rb1.get(1) == 2, "0番目の要素は 2 であるはずです"
assert rb1.get(2) == 3, "0番目の要素は 3 であるはずです"
assert rb1.len() == 3, "3つの要素が入っているため,長さは3であるはずです"
rb2 = RingBuffer()
assert rb2.get(0) == None, "何も要素が入っていないため,None であるはずです"
rb2.add("item1")
rb2.add("item2")
assert rb2.len() == 2, "2つの要素が入っているため,長さは2であるはずです"
assert rb2.get(5) == None, "5番目の要素は存在しないため,None であるはずです"
以下の図は,上記の rb1
,rb2
の動作イメージです.クリックすると更新されます.

課題08-3 拡張子ごとのワードカウント #
難易度 ⭐⭐⭐
指定されたディレクトリ以下のファイルを再帰的に検索し,拡張子ごとに文字数,行数,ファイル数を数えるプログラムを作成してください.
そして,拡張子ごとに文字数,行数,ファイル数を表示してください.
word_count.py
というファイル名で保存してください.
WordCounts
はself.types
というディクショナリをもち,拡張子をキーとして,Counts
オブジェクトを値として持ちます.Counts
オブジェクトは,拡張子ごとの文字数,行数,ファイル数を保持します.Counts
オブジェクトは,最初に拡張子が見つかったときに,初期化されます.- また,
Counts
オブジェクトのparse
メソッドは,当該拡張子を持つファイルが見つかった時に呼び出されます.- そのため,
parse
メソッドが呼び出されると,ファイル数を+1
し,ファイルの内容を読み込んで文字数と行数を数えて,self.lines
とself.chars
に加算します.
- そのため,
import os
import sys
class Counts:
def __init__(self):
# 文字数(chars),行数(lines),ファイル数(files)を初期化する.
def parse(self, file):
with open(file, 'r') as f:
# ファイルの内容を読み込んで,文字数と行数を数える.
# ファイル数を1増やす.
def str(self):
return f"files: {self.files:5}, chars: {self.chars:5}, lines: {self.lines:5}"
class WordCounts:
def __init__(self):
self.types = {}
def traverse(self, path):
if os.path.isdir(path): # ディレクトリかどうかを判定する.
for p in os.listdir(path): # ディレクトリ内のファイル,ディレクトリを列挙する.
new_path = os.path.join(path, p) # ディレクトリ名とファイル名を結合する.
self.traverse(new_path) # ディレクトリを再帰的に探索する.
else: # ディレクトリではない場合(ファイルの場合)
ext = # 拡張子を取得する(_find_ext を呼び出す).
if ext not in self.types: # ディクショナリに拡張子に対応する Counts が存在するか.
pass # 存在しなければ,新たに作成して,types に追加する.
self.types[ext].parse(path) # ファイルを解析する.
def _find_ext(self, path): # ファイル名を受け取り,拡張子を返す.
ext = os.path.splitext(path)[-1] # 拡張子を取得する(一番最後の要素を取得する).
if ext == '': # 拡張子が存在しない場合
return os.path.basename(path) # ファイル名を返す.
return ext # 拡張子を返す.
def print(self):
for ext, counts in self.types.items(): # 拡張子と Counts のペアを取り出す.
print(f"{ext:12}: {counts.str()}") # 結果を出力する.
wc = WordCounts()
for arg in sys.argv[1:]:
wc.traverse(arg)
wc.print()
実行例 #
以下の helloworld.zip
をダウンロードして展開してできたディレクトリ,helloworld
を指定すると以下のような結果になります.
$ python3 word_count.py helloworld
.mod files: 1, chars: 45, lines: 3
LICENSE files: 1, chars: 7048, lines: 121
Dockerfile files: 1, chars: 236, lines: 11
.md files: 1, chars: 565, lines: 14
.go files: 1, chars: 262, lines: 20