Problem
Write a function that replaces the words in raw
with the words in code_words
such that the first occurrence of each word in raw
is assigned the first unassigned word in code_words
. If the code_words
list is too short, raise an error. code_words
may contain duplicates, in which case the function should ignore/skip them.
Examples:
encoder(["a"], ["1", "2", "3", "4"]) → ["1"]
encoder(["a", "b"], ["1", "2", "3", "4"]) → ["1", "2"]
encoder(["a", "b", "a"], ["1", "1", "2", "3", "4"]) → ["1", "2", "1"]
Solution
def encoder(raw, code_words):
cw = iter(code_words)
code_by_raw = {} # map of raw item to code item
result = []
seen = set() # for ignoring duplicate code_words
for r in raw:
if r not in code_by_raw:
for code in cw: # cw is iter(code_words), "persistent pointer"
if code not in seen:
seen.add(code)
break
else: # nobreak; ran out of code_words
raise ValueError("not enough code_words")
code_by_raw[r] = code
result.append(code_by_raw[r])
return result
Questions
My main concern is the use of cw
as a "persistent pointer". Specifically, might people be confused when they see for code in cw
?
What should be the typical best practices in this case?
Might it be better if I used the following instead?
try:
code = next(cw)
while code in seen:
code = next(cw)
except StopIteration:
raise ValueError("not enough code_words")
else:
seen.add(code)