I had a hard time with the premise of the problem itself, as I thought that the approach was highly inflexible because it made 2 assumptions that would make actually using this code in reality very impractical.
You may assume that (1) the string has sufficient space at the end to hold the additional characters and (2) that you are given the true length of the string.
This became apparent when I started writing a docstring to explain what the function does...
def urlify(char_list: list, true_length: int) -> list:
"""
Replace each space '_' character element within a character list with
the characters '%20' as individual character elements.
NOTE: This logic assumes that the true_length of the string, i.e., the total amount of characters
minus all trailing spaces, will be provided, and that the input string will have exactly
as many trailing spaces as are needed to replace each ' ' space with 3 characters.
"""
For instance, I would expect with a function like this, that I could do something like this:
hello_string = 'Hello, World!'
urlified_string = urlify(list(hello_string), len(hello_string))
Which satisfies the exact length criteria just fine, but since it is missing the extra spaces, I get a IndexError: list assignment index out of range
. So I have to do some extra work to make sure to add just the right amount of trailing spaces...
urlified_string = urlify(list(hello_string + ' '), len(hello_string))
So the question now becomes:
###Can we make this code more flexible and reusable?
First, since this code is meant to take a string and turn it into a "URLified" string, we should adapt our functions accordingly, to avoid making the caller do the conversions to lists, etc.
def count_spaces_in_string(string: str) -> int:
return sum(1 for char in list(string) if char == ' ')
count_spaces_in_string('Mr John Smith ') #-> 6
We could also limit ourselves to only counting the spaces that matter, by stripping any trailing and leading spaces with string.strip()
. This way, we can approach the challenge differently and not have to rely on assumption (1) to be true:
def count_spaces_in_string(string: str) -> int:
return sum(1 for char in list(string.strip()) if char == ' ')
count_spaces_in_string('Mr John Smith ') #-> 2
This will of course cause your bigger function to no longer work correctly until we make a few changes to it.
We can also do away with the need for assumption (2) by, again, using string.strip()
to get the true_length
within the function, thus eliminating the need to pass it as argument:
def urlify_string(string: str) -> str:
"""
Replace each space '_' character element within a string with
the escape characters '%20'.
"""
true_length = len(string.strip()) #-> 13
num_spaces = count_spaces_in_string(string) #-> 2
urlified_length = true_length + (2 * num_spaces) #-> 17
Notice that I shortened the docstring to how the function should really behave.
Once you free yourself of all those assumptions, the logic to actually do what you want to do to any string becomes extremely simple. In fact with this updated logic, we don't even need to account for the length of the string ("true" or otherwise) or the number of spaces at all, making the first function obsolete. Here is a runnable demo on repl.it
Don't ask me about the time and space complexity of this approach; I'm not sure. I would argue this version is far simpler to use and to understand, and in my opinion that has a lot of value, often more than marginal complexity optimizations.
def urlify_string(string: str) -> str:
"""
Replace each space '_' character element within a string with
the escape characters '%20'.
"""
true_string = string.strip()
char_list = []
for char in list(true_string):
if char == ' ':
char_list.append('%')
char_list.append('2')
char_list.append('0')
else:
char_list.append(char)
return ''.join(char_list)
print(urlify_string('Mr John Smith ')) #-> Mr%20John%20Smith
print(urlify_string('Mr John Smith')) #-> Mr%20John%20Smith
print(urlify_string(' Mr John Smith ')) #-> Mr%20John%20Smith
print(urlify_string('Hello, World!')) #-> Hello,%20World!