I'm trying to make a function that takes in a string as an input. It then moves the capital letters in the string to the front, and capitalizes lower-case letters. Lower-case letters and spaces should be kept in the same position relative to their location in the original string.
For example:
unravel_message(' neHAw moPPnthY')
should return 'HAPPY NEW MONTH'
as the output.
and unravel_message('ALL CAPITALS')
should return 'ALLCAPITALS '
as the output.
(the space remains in the same location; only the capitals are moved back)
My Attempt:
def unravel_message(word):
return ''.join([i for i in word if i == i.upper()]) ''.join([i.upper() for i in word if i == i.lower()])
for my function, unravel_message(' neHAw moPPnthY')
outputs ' HA PPY NEW MONTH'
. Which isn't quite right. I think this may be because of the ''.join()
. I would like to revise this function to use a single list comprehension wihtout imports if possible. If the inputs are all lowercase, I would also like to include an assertion statement addressing an error but I'm not sure how to do this.
CodePudding user response:
Timsort is stable, which means that you can get what you want with something like
>>> ''.join(sorted(message, key=lambda c: not c.isupper())).upper()
'HAPPY NEW MONTH'
The trick is that booleans are a subclass of integers in python. The key returns False == 0
for elements you want to move to the beginning, and True == 1
for elements that stay. You need to use lambda c: not c.isupper()
because spaces and other characters will move back if you use str.islower
as the key.
CodePudding user response:
Here is a solution that uses a single list comprehension without imports. It is also linear in time with the length of the string unlike sorting solutions with have higher time complexity of O(n log n). It also has an assertion statement flagging strings with no uppercase letters (i.e., all alpha characters are lowercase).
def unravel_message(s):
assert any('A' <= c <= 'Z' for c in s)
return (duo := list(map(lambda x: ''.join(x).replace(chr(0), ''), zip(*[(c, chr(0)) if c.isupper() else (chr(0), c.upper()) for c in s]))))[0] duo[1]
x = unravel_message(' neHAw moPPnthY')
print(x)
x = unravel_message(' no uppercase letters')
Output:
HAPPY NEW MONTH
Traceback (most recent call last):
File "C:\python\test.py", line 7, in <module>
x = unravel_message(' no uppercase letters')
File "C:\python\test.py", line 2, in unravel_message
assert any('A' <= c <= 'Z' for c in s)
AssertionError
Note that the solution uses the walrus operator :=
to make it a one-liner. If you are using Python earlier than version 3.8, you can do this instead:
def unravel_message(s):
assert any('A' <= c <= 'Z' for c in s)
duo = list(map(lambda x: ''.join(x).replace(chr(0), ''), zip(*[(c, chr(0)) if c.isupper() else (chr(0), c.upper()) for c in s])))
return duo[0] duo[1]