Basis¶
Wat een tekst over zichzelf zegt, korter¶
Opdracht: Wat een tekst over zichzelf zegt, korter
De gegeven code uit de opgave:
# Dit notebook staat in solutions/ en de teksten in problems/assets/teksten/,
# vandaar het pad terug. In de opgave zelf is dat "assets/teksten/".
TEKSTEN = "../problems/assets/teksten/"
LEESTEKENS = ".,!?;:"
def read_text(filename):
"""Leest een heel bestand en geeft de inhoud terug als één string."""
with open(filename) as file:
return file.read()
def word_list(text):
"""Geeft de woorden van text in kleine letters, zonder leestekens."""
schoon = ""
for teken in text.lower():
if teken in LEESTEKENS:
schoon = schoon + " "
else:
schoon = schoon + teken
return schoon.split()
Stap 1: long_words(words, n)¶
def long_words(words, n):
"""Geeft de woorden uit words die langer zijn dan n letters."""
return [word for word in words if len(word) > n]
assert long_words(["de", "vuurtoren", "draait"], 5) == ["vuurtoren", "draait"]
assert long_words([], 5) == []
assert long_words(word_list(read_text(TEKSTEN + "vuurtoren.txt")), 11) == [
"zesenvijftig",
"tweehonderdzesendertig",
"vuurtorenwachter",
"geschiedenis",
"tegenwoordig",
]
Stap 2: count_words(words)¶
def count_words(words):
"""Telt hoe vaak elk woord voorkomt."""
# Een lus: die loopt de woorden één keer langs en werkt per stap één
# telling bij. De comprehension loopt voor elk woord de hele lijst opnieuw
# langs.
counts = {}
for word in words:
counts[word] = counts.get(word, 0) + 1
return counts
assert count_words(["spam", "spam", "taart"]) == {"spam": 2, "taart": 1}
assert count_words([]) == {}
assert count_words(word_list(read_text(TEKSTEN + "kort.txt")))["taarten"] == 3
De dict comprehension geeft dezelfde dictionary, maar words.count(word) loopt
de hele lijst langs, en dat gebeurt voor elk verschillend woord opnieuw. Voor
vuurtoren.txt zijn dat 134 rondes door 227 woorden, tegen één ronde voor de
lus. .get uit week 1 maakt de lus korter; de if ... else uit week 1 is net
zo goed.
Stap 3: words_used_once(counts)¶
def words_used_once(counts):
"""Telt hoeveel woorden precies één keer voorkomen."""
return sum([1 for count in counts.values() if count == 1])
assert words_used_once({"spam": 2, "taart": 1}) == 1
assert words_used_once({}) == 0
assert (
words_used_once(count_words(word_list(read_text(TEKSTEN + "vuurtoren.txt")))) == 94
)
counts.values() geeft alleen de aantallen, want de woorden doen hier niet
mee. len([count for count in counts.values() if count == 1]) telt ook, en is
net zo goed.
Stap 4: ngram_loop(word, n)¶
def ngram_loop(word, n):
"""Geeft de overlappende stukjes van n letters van word, op volgorde."""
result = []
for i in range(len(word) - n + 1):
result.append(word[i : i + n])
return result
def ngram(word, n):
"""Geeft de overlappende stukjes van n letters van word, op volgorde."""
return [word[i : i + n] for i in range(len(word) - n + 1)]
assert ngram_loop("toren", 2) == ["to", "or", "re", "en"]
assert ngram_loop("toren", 5) == ["toren"]
assert ngram_loop("toren", 6) == []
for word in ["", "a", "vuurtoren"]:
for n in [1, 2, 3]:
assert ngram_loop(word, n) == ngram(word, n)
De vierkante haken worden result = [] en return result, het deel na for
wordt de lus, en wat vooraan stond, wordt de append. Is n groter dan het
woord, dan is len(word) - n + 1 nul of negatief; range levert dan niets op,
en beide versies geven [].
Stap 5: count_table(counts)¶
def count_table(counts):
"""Geeft de telling als lijst van lijsten [woord, aantal]."""
return [[word, count] for word, count in counts.items()]
assert count_table({"spam": 2, "taart": 1}) == [["spam", 2], ["taart", 1]]
assert count_table({}) == []
assert count_table(count_words(word_list(read_text(TEKSTEN + "vuurtoren.txt"))))[0] == [
"de",
8,
]
Een lijst van lijsten met één for: wat erin komt, is zelf een lijst.