python_coding_challenge

【 Python coding challenge 】Gutenberg Project からダウンロードする実際の古典を題材に、登場人物インデックスを作成しよう! Python Programming Interview の準備にもなります【解答例】 投稿一覧へ戻る

Tags: challenge , programming , python

Published 2020年8月3日21:16 by T.Tsuyoshi

プログラムチャレンジです。是非自分なりのコーディングをしてみてください。問題は こちら から。


様々な実装方法が考えられます。解答例を参考にしてみてください。


ダウンロードしたテキストファイルを一度ファイルへ書き出し、再度 readlines() を利用して読み込む、という方法を取っている方もいました。


import math
from collections import defaultdict
import requests


class CreateCharacterIndex:

# 登場人物リスト:
# それぞれの人物ごとに登場しているページ番号を保存し、最終的にインデックスを作成する

CHARACTERS = ["Kurtz", "manager", "Russian", "pilgrims", "cannibals", "aunt", "brickmaker", "Accountant",
"helmsman", "mistress", "intended", "Marlow", "Fresleven"]


def __init__(self):
self.data = []

# defaultdict を利用することで、初期値に空のリストが割り当てられるため手間なしです
self.character_index = defaultdict(list)


def download_data(self, url):
"""
指定された URL のテキストファイルを取得し、改行文字で各要素に分けられたリストを作成、保存する。

:param url: 取得するファイルの URL
"""

res = requests.get(url)
if res.status_code != 200:
print("データが取得できませんでした")
return

self.data = res.text.splitlines()
self.make_index()


def get_page_content(self, lines_per_page=45, page_no=1):
"""
ダウンロードしたテキストから、任意の行数で構成される「ページ」を作出し、
page_no パラメータに相当するページのコンテンツを提供する。

:param lines_per_page: 1ページに含まれる行数。
:param page_no: 取得したいページ番号
:return: page_no ページに含まれるコンテンツ
"""

total_page = math.ceil(len(self.data) / lines_per_page)
if page_no <= 0 or total_page < page_no:
raise ValueError(f"ページ番号が不正です。1 から {total_page} の間でなければなりません。")

start = lines_per_page * (page_no - 1)
end = lines_per_page * page_no
return self.data[start:end]

def make_index(self):
"""
各ページを走査し、該当する登場人物が含まれていれば、それぞれの登場人物ごとにページ番号を保存する。
"""

page_no = 1
while True:
# 1ページから最終ページまでループしますが、例外が投げられることで最終ページまで到達したことを判断しています
try:
content = ' '.join(self.get_page_content(page_no=page_no))
for name in CreateCharacterIndex.CHARACTERS:
if name in content:
# defaultdict を利用しているため、キーがまだ辞書内にない場合でも空のリストが割り当てられるためエラーになりません
self.character_index[name].append(page_no)
page_no += 1
except ValueError:
break

def print_index(self):
"""
{'登場人物A': [3, 16], '登場人物B': [11, 34, 36],...} という形式の辞書を整形して登場人物インデックスを表示する。

インデックスは大文字小文字を区別せず登場人物のアルファベット順表示とする。
登場するページ番号には p3, p16 のように先頭に 'p' の文字を付加すること。
"""

# sorted() と lambda 式の併用で、小文字だけの登場人物名を比較して並べ替えています
for name, pages in sorted(self.character_index.items(), key=lambda x: x[0].lower()):
pages = ['p'+str(page) for page in pages]
print(f"{name:<13}: {', '.join(pages)}")


url = "http://www.gutenberg.org/cache/epub/526/pg526.txt"

myindex = CreateCharacterIndex()
myindex.download_data(url)
myindex.print_index()

# Accountant : p2
# aunt : p7, p10, p24, p57, p65, p68
# brickmaker : p23, p59
# cannibals : p32
# Fresleven : p7, p8
# helmsman : p42, p43, p48
# intended : p30, p65
# Kurtz : p17, p20, p21, p22, p23, p24, p25, p26, p29, p30, p31, p33, p35, p36, p40, p41, p44, p45, p46, p47, p48, p49, p50, p51, p52, p53, p54, p55, p56, p58, p59, p60, p61, p62, p64, p65, p66, p67, p68, p69, p70, p72, p75
# manager : p19, p22, p23, p24, p26, p28, p29, p30, p31, p33, p36, p40, p44, p46, p48, p49, p50, p54, p57, p59, p65, p66, p68, p72
# Marlow : p2, p3, p4, p6, p7, p26, p32, p45, p75
# mistress : p4
# pilgrims : p21, p22, p24, p25, p27, p28, p32, p33, p35, p36, p37, p38, p39, p40, p42, p48, p50, p57, p58, p62, p64, p65, p66, p67
# Russian : p50, p51, p54, p56, p57, p59

この投稿をメールでシェアする

0 comments

コメントはまだありません。

コメントを追加する(不適切と思われるコメントは削除する場合があります)