-
Notifications
You must be signed in to change notification settings - Fork 1
/
Portmanteau.py
executable file
·93 lines (79 loc) · 4.37 KB
/
Portmanteau.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# Unit 6: Fun with Words
"""
A portmanteau word is a blend of two or more words, like 'mathelete',
which comes from 'math' and 'athelete'. You will write a function to
find the 'best' portmanteau word from a list of dictionary words.
Because 'portmanteau' is so easy to misspell, we will call our
function 'natalie' instead:
natalie(['word', ...]) == 'portmanteauword'
In this exercise the rules are: a portmanteau must be composed of
three non-empty pieces, start+mid+end, where both start+mid and
mid+end are among the list of words passed in. For example,
'adolescented' comes from 'adolescent' and 'scented', with
start+mid+end='adole'+'scent'+'ed'. A portmanteau must be composed
of two different words (not the same word twice).
That defines an allowable combination, but which is best? Intuitively,
a longer word is better, and a word is well-balanced if the mid is
about half the total length while start and end are about 1/4 each.
To make that specific, the score for a word w is the number of letters
in w minus the difference between the actual and ideal lengths of
start, mid, and end. (For the example word w='adole'+'scent'+'ed', the
start,mid,end lengths are 5,5,2 and the total length is 12. The ideal
start,mid,end lengths are 12/4,12/2,12/4 = 3,6,3. So the final score
is
12 - abs(5-3) - abs(5-6) - abs(2-3) = 8.
yielding a score of 12 - abs(5-(12/4)) - abs(5-(12/2)) -
abs(2-(12/4)) = 8.
The output of natalie(words) should be the best portmanteau, or None
if there is none.
Note (1): I got the idea for this question from
Darius Bacon. Note (2): In real life, many portmanteaux omit letters,
for example 'smoke' + 'fog' = 'smog'; we aren't considering those.
Note (3): The word 'portmanteau' is itself a portmanteau; it comes
from the French "porter" (to carry) + "manteau" (cloak), and in
English meant "suitcase" in 1871 when Lewis Carroll used it in
'Through the Looking Glass' to mean two words packed into one. Note
(4): the rules for 'best' are certainly subjective, and certainly
should depend on more things than just letter length. In addition to
programming the solution described here, you are welcome to explore
your own definition of best, and use your own word lists to come up
with interesting new results. Post your best ones in the discussion
forum. Note (5) The test examples will involve no more than a dozen or so
input words. But you could implement a method that is efficient with a
larger list of words.
"""
import itertools
def natalie(words):
"Find the best Portmanteau word formed from any two of the list of words."
results = set()
for w1, w2 in itertools.permutations(words, 2):
for i in range(1, len(w1)-1):
if w2[-i:] == w1[:i]:
s = len(w2[:-i])
m = len(w2[-i:])
e = len(w1[i:])
t = s+m+e
results.add((t - abs(t/4.-s) - abs(t/2.-m) - abs(t/4.-e) ,w2 + w1[i:]))
if results:
return max(results)[1]
def test_natalie():
"Some test cases for natalie"
assert natalie(['adolescent', 'scented', 'centennial', 'always', 'ado']) in ('adolescented','adolescentennial')
assert natalie(['eskimo', 'escort', 'kimchee', 'kimono', 'cheese']) == 'eskimono'
assert natalie(['kimono', 'kimchee', 'cheese', 'serious', 'us', 'usage']) == 'kimcheese'
assert natalie(['circus', 'elephant', 'lion', 'opera', 'phantom']) == 'elephantom'
assert natalie(['programmer', 'coder', 'partying', 'merrymaking']) == 'programmerrymaking'
assert natalie(['int', 'intimate', 'hinter', 'hint', 'winter']) == 'hintimate'
assert natalie(['morass', 'moral', 'assassination']) == 'morassassination'
assert natalie(['entrepreneur', 'academic', 'doctor', 'neuropsychologist', 'neurotoxin', 'scientist', 'gist']) in ('entrepreneuropsychologist', 'entrepreneurotoxin')
assert natalie(['perspicacity', 'cityslicker', 'capability', 'capable']) == 'perspicacityslicker'
assert natalie(['backfire', 'fireproof', 'backflow', 'flowchart', 'background', 'groundhog']) == 'backgroundhog'
assert natalie(['streaker', 'nudist', 'hippie', 'protestor', 'disturbance', 'cops']) == 'nudisturbance'
assert natalie(['night', 'day']) == None
assert natalie(['dog', 'dogs']) == None
assert natalie(['test']) == None
assert natalie(['']) == None
assert natalie(['ABC', '123']) == None
assert natalie([]) == None
return 'tests pass'
print test_natalie()