csv
まず、モジュールを手動で解析しようとするのではなく、すでにモジュールを使用していることを願っています。
第二に、あなたの質問からは完全には明らかではありませんが、データを読んでいるときに、データから単純なツリー構造を構築しようとしているようです。
だから、このようなもの?
with open('book.csv') as book:
chapters = collections.defaultdict(collections.defaultdict(list))
book.readline() # to skip the headers
for chapter_name, section_name, lesson_name in csv.reader(book):
chapters[chapter_name][section_name].append(lesson_name)
もちろん、これは「連想ツリー」が必要であることを前提としていdict
ますdict
。list
sのような、より通常の線形ツリー、list
または「親ポインター」の形式の暗黙のツリーは、さらに単純です。
たとえば、次のように定義されたクラスがあるとします。
class Chapter(object):
def __init__(self, name):
self.name = name
class Section(object):
def __init__(self, chapter, name):
self.chapter = chapter
self.name = name
class Lesson(object):
def __init__(self, section, name):
self.section = section
self.name = name
そしてdict
、それぞれに、名前をオブジェクトにマッピングする必要があります。それで:
with open('book.csv') as book:
chapters, sections, lessons = {}, {}, {}
book.readline() # to skip the headers
for chapter_name, section_name, lesson_name in csv.reader(book):
chapter = chapters.setdefault(chapter_name, Chapter(chapter_name))
section = sections.setdefault(section_name, Section(chapter, section_name))
lesson = lessons.setdefault(lesson_name, Lesson(section, lesson_name))
これで、ランダムなレッスンを選択して、その章とセクションを印刷できます。
lesson = random.choice(lessons.values())
print('Chapter {}, Section {}: Lesson {}'.format(lesson.section.chapter.name,
lesson.section.name, lesson.name))
最後に覚えておくべきことは、この例では、親には子への参照がないため、親の参照によって循環参照が発生することはありません。しかし、それが必要な場合はどうなりますか?
class Chapter(object):
def __init__(self, name):
self.name = name
self.sections = {}
class Section(object):
def __init__(self, chapter, name):
self.chapter = chapter
self.name = name
self.lessons = {}
# ...
chapter = chapters.setdefault(chapter_name, Chapter(chapter_name))
section = sections.setdefault(section_name, Section(chapter, section_name))
chapters[section_name] = section
これまでのところ、とても良いです…しかし、これらすべてのオブジェクトを使い終わったらどうなりますか?それらには循環参照があり、ガベージコレクションの問題を引き起こす可能性があります。克服できない問題ではありませんが、ほとんどの実装でオブジェクトがすぐに収集されないことを意味します。たとえば、CPythonでは、通常、最後の参照がスコープ外になるとすぐに収集されますが、循環参照がある場合は発生しないため、サイクル検出器の次のパスまで何も収集されません。これに対する解決策はweakref
、親ポインター(またはweakref
子へのsのコレクション)にaを使用することです。