Slightly improved version (deals with multiple characters together
instead of one at a time):
# Pack.py
def Pack(Words):
if not Words:
return ''
# The method is to build up the result by adding letters at the beginning
# and working forward, and by adding letters at the end, working backwards,
# meanwhile shrinking the words in the list.
Words = list(Words) # Don't mutate the original
Initial = ''
Final = ''
while True:
# It is safe to add an initial letter (of one or more of the
words) if
# EITHER There is no word that contains it as
# a non-initial letter but not as an initial letter.
# OR All words start with it.
while True:
FirstLetters = set(w[0] for w in Words)
FirstLettersSafe = sorted(ch for ch in FirstLetters if all(w[0]==ch for w in Words)
or not any(ch in w[1:] and w[0]!=ch for w in Words))
# sorted() to make the answer deterministic
# (not dependent on set ordering)
if not FirstLettersSafe:
break
AnyProgress = True
Initial += ''.join(FirstLettersSafe) # Build up the
answer from the beginning
Words = [ (w[1:] if w[0] in FirstLettersSafe else w) for w
in Words ]
Words = [ w for w in Words if w != '']
if not Words:
return Initial + Final
# It is safe to add a final letter (of one or more of the words) of
# EITHER There is no word that contains it as
# a non-final letter but not as a final letter.
# OR All words end with it.
while True:
LastLetters = set(w[-1] for w in Words)
LastLettersSafe = sorted(ch for ch in LastLetters if all(w[-1]==ch for w in Words)
or not any(ch in w[:-1] and w[-1]!=ch for w in Words))
# sorted() to make the answer deterministic
# (not dependent on set ordering)
if not LastLettersSafe:
break
Final = ''.join(LastLettersSafe) + Final # Build up the
answer from the end
Words = [ (w[:-1] if w[-1] in LastLettersSafe else w) for w
in Words ]
Words = [ w for w in Words if w != '']
if not Words:
return Initial + Final
if not (FirstLettersSafe or LastLettersSafe):
break # stuck
# Try all the possibilities for the next letter to add at the
beginning,
# with recursive calls, and pick one that gives a shortest answer:
BestResult = None
for ch in FirstLetters:
Words2 = list( (w[1:] if w[0] == ch else w) for w in Words )
Words2 = [ w for w in Words2 if w != '' ]
res = ch + Pack(Words2)
if BestResult is None or len(res) < len(BestResult):
BestResult = res
return Initial + BestResult + Final
print(Pack(['APPLE', 'PIE', 'APRICOT', 'BANANA', 'CANDY']))
Rob Cliffe
On Thursday, March 2, 2023 at 11:10:37 AM UTC-8, Rob Cliffe wrote:
Slightly improved version (deals with multiple characters together instead of one at a time):
# Pack.py
def Pack(Words):
if not Words:
return ''
# The method is to build up the result by adding letters at the beginning # and working forward, and by adding letters at the end, working backwards,
# meanwhile shrinking the words in the list.
Words = list(Words) # Don't mutate the original
Initial = ''
Final = ''
while True:
# It is safe to add an initial letter (of one or more of the words) if
# EITHER There is no word that contains it as
# a non-initial letter but not as an initial letter.
# OR All words start with it.
thanks.... i'd be surprised to find a shorter answer.
bappricnanadloety =17 chars
On Friday, March 3, 2023 at 12:00:00 PM UTC-8, Hen Hanna wrote:
On Thursday, March 2, 2023 at 11:10:37 AM UTC-8, Rob Cliffe wrote:
Slightly improved version (deals with multiple characters together instead of one at a time):
# Pack.py
def Pack(Words):
if not Words:
return ''
# The method is to build up the result by adding letters at the beginning
# and working forward, and by adding letters at the end, working backwards,
# meanwhile shrinking the words in the list.
Words = list(Words) # Don't mutate the original
Initial = ''
Final = ''
while True:
is ths (above) the same as this?# It is safe to add an initial letter (of one or more of the words) if
# EITHER There is no word that contains it as
# a non-initial letter but not as an initial letter.
# OR All words start with it.
It is safe to add an initial letter of (subset of) the words if
All words start with it.
OR ELSE
The remaining words don't contain that letter.
thanks.... i'd be surprised to find a shorter answer.
bappricnanadloety =17 chars
py packBad.pySyntaxError: Non-UTF-8 code starting with '\xa0' in file C:\pypy3.9...........\packBad.py on line 3, but no encoding declared.........
equivalent values. The equivalent value of xa0, for example, is a space.To remove xa0 from string in Python, we can use the value NFKD in the normalize() function, which is an abbreviation for Normal Form KD . The use of NFKD in the normalize() function results in the substitution of all the characters into their
Haven’t look at it all in detail, but I’d replace the list comprehensions with a loop:Why?
CopyOfWords = list(Words)
Words = [(w[1:] if w[0] == ch else w) for w in Words]
Words = [w for w in Words if w != '']
nextWords = []
for w in CopyOfWords:
if w[0] != ch:
nextWords.append(w)
elif len(w) > 1:
nextWords.append(w[1:])
assert Words == nextWords
From: Python-list <python-list-bounces+gweatherby=uchc.edu@python.org> on behalf of Rob Cliffe via Python-list <python-list@python.org>listinfo/python-list__;!!Cn_UX_p3!l3ysx0BUPZBdKdwb9F8mw4BAE2UIflvNqWeZLfALY2kjEo9e4KTy6fEYoGCTileOUtYe0yp6nL18ymdOguC3TGagEA$>
Date: Thursday, March 2, 2023 at 2:12 PM
To: python-list@python.org <python-list@python.org>
Subject: Re: Packing Problem
*** Attention: This is an external email. Use caution responding, opening attachments or clicking on links. ***
Slightly improved version (deals with multiple characters together
instead of one at a time):
# Pack.py
def Pack(Words):
if not Words:
return ''
# The method is to build up the result by adding letters at the beginning
# and working forward, and by adding letters at the end, working backwards,
# meanwhile shrinking the words in the list.
Words = list(Words) # Don't mutate the original
Initial = ''
Final = ''
while True:
# It is safe to add an initial letter (of one or more of the
words) if
# EITHER There is no word that contains it as
# a non-initial letter but not as an initial letter.
# OR All words start with it.
while True:
FirstLetters = set(w[0] for w in Words)
FirstLettersSafe = sorted(ch for ch in FirstLetters if
all(w[0]==ch for w in Words)
or not any(ch in w[1:] and w[0]!=ch for w in Words))
# sorted() to make the answer deterministic
# (not dependent on set ordering)
if not FirstLettersSafe:
break
AnyProgress = True
Initial += ''.join(FirstLettersSafe) # Build up the
answer from the beginning
Words = [ (w[1:] if w[0] in FirstLettersSafe else w) for w
in Words ]
Words = [ w for w in Words if w != '']
if not Words:
return Initial + Final
# It is safe to add a final letter (of one or more of the words) of
# EITHER There is no word that contains it as
# a non-final letter but not as a final letter.
# OR All words end with it.
while True:
LastLetters = set(w[-1] for w in Words)
LastLettersSafe = sorted(ch for ch in LastLetters if
all(w[-1]==ch for w in Words)
or not any(ch in w[:-1] and w[-1]!=ch for w in Words))
# sorted() to make the answer deterministic
# (not dependent on set ordering)
if not LastLettersSafe:
break
Final = ''.join(LastLettersSafe) + Final # Build up the answer from the end
Words = [ (w[:-1] if w[-1] in LastLettersSafe else w) for w
in Words ]
Words = [ w for w in Words if w != '']
if not Words:
return Initial + Final
if not (FirstLettersSafe or LastLettersSafe):
break # stuck
# Try all the possibilities for the next letter to add at the beginning,
# with recursive calls, and pick one that gives a shortest answer:
BestResult = None
for ch in FirstLetters:
Words2 = list( (w[1:] if w[0] == ch else w) for w in Words )
Words2 = [ w for w in Words2 if w != '' ]
res = ch + Pack(Words2)
if BestResult is None or len(res) < len(BestResult):
BestResult = res
return Initial + BestResult + Final
print(Pack(['APPLE', 'PIE', 'APRICOT', 'BANANA', 'CANDY']))
Rob Cliffe
-- https://urldefense.com/v3/__https://mail.python.org/mailman/listinfo/python-list__;!!Cn_UX_p3!l3ysx0BUPZBdKdwb9F8mw4BAE2UIflvNqWeZLfALY2kjEo9e4KTy6fEYoGCTileOUtYe0yp6nL18ymdOguC3TGagEA$<https://urldefense.com/v3/__https:/mail.python.org/mailman/
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 300 |
Nodes: | 16 (2 / 14) |
Uptime: | 62:36:08 |
Calls: | 6,712 |
Files: | 12,244 |
Messages: | 5,355,897 |