Say we have a function that translates the morse symbols:
.->-.-->...-
If we apply this function twice, we get e.g:
. -> -. -> ...--.
Given an input string and a number of repetitions, want to know the length of the final string. (Problem 1 from the Flemish Programming Contest VPW, taken from these slides which provide a solution in Haskell).
For the given inputfile
4
. 4
.- 2
-- 2
--... 50
We expect the solution
44
16
20
34028664377246354505728
Since I don’t know Haskell, this is my recursive solution in Python that I came up with:
def encode(msg, repetition, morse={'.': '-.', '-': '...-'}):
if isinstance(repetition, str):
repetition = eval(repetition)
while repetition > 0:
newmsg = ''.join(morse[c] for c in msg)
return encode(newmsg, repetition-1)
return len(msg)
def problem1(fn):
with open(fn) as f:
f.next()
for line in f:
print encode(*line.split())
which works for the first three inputs but dies with a memory error for the last input.
How would you rewrite this in a more efficient way?
Edit
Rewrite based on the comments given:
def encode(p, s, repetition):
while repetition > 0:
p,s = p + 3*s, p + s
return encode(p, s, repetition-1)
return p + s
def problem1(fn):
with open(fn) as f:
f.next()
for line in f:
msg, repetition = line.split()
print encode(msg.count('.'), msg.count('-'), int(repetition))
Comments on style and further improvements still welcome
Consider that you don’t actually have to output the resulting string, only the length of it. Also consider that the order of ‘.’ and ‘-‘ in the string do not affect the final length (e.g. “.- 3” and “-. 3” produce the same final length).
Thus, I would give up on storing the entire string and instead store the number of ‘.’ and the number of ‘-‘ as integers.