Write functions
You show the reversal of two strings: John Doe
and Happy new year! 2022
. But your code can only reverse one string. If you wanted to reverse the other string as well, you'd have to duplicate the code.
Instead, write a function. They can be called multiple times.
def reverse_words(sentence):
... your code here ...
return final_str
str1 = "John Doe"
reversed1 = reverse_words(str1)
print(f"string: {str1}\nlen: {len(str1)}")
print(f"Reversed_string: {reversed1}\nlen: {len(reversed1)}")
str2 = "Happy new year! 2022"
reversed2 = reverse_words(str2)
print(f"string: {str2}\nlen: {len(str2)}")
print(f"Reversed_string: {reversed2}\nlen: {len(reversed2)}")
When writing functions, use type-hints and """doc-strings"""
to provide additional information about how to use the function:
def reverse_words(sentence: str) -> str:
"""
Reverse the words of a string.
>>> reverse_words("John Doe")
'Doe John'
>>> reverse_words("Happy new year! 2022")
'2022 year! new Happy'
"""
... your code here ...
return final_str
With the above function definition, help(reverse_words)
will describe the function in much the same way that help(print)
describes the print function.
As a bonus, the >>>
text in the """doc-string"""
can be used for testing, via the doctest
module.
Variable Naming
What is space_counter
? At first read, I thought you were counting spaces, but it turns out that isn't quite correct:
space_counter = 0
for ...:
if char == " ":
space_counter += 1
if space_counter == 1:
...
elif space_counter == 2:
...
space_counter = 1
The "counter" starts at 0. At the first space, it increments to 1 and one action is performed. At the second and any subsequent space, it increments to 2 and is immediately reset to 1. Since it can only take on the values 0, 1 or 2, it is not really a counter.
It appears you are trying to do something different on the first space verses any subsequent space. A boolean "flag" is more descriptive in these cases:
seen_space = False
for ...:
if char == " ":
if not seen_space:
...
seen_space = True
else:
...
temp
, a_str
, and b_str
are all similarly not descriptive variable names. final_str
seems more descriptive, but it is used in statements like final_str = temp + " " + final_str
, which means its value is not really "final", so again, it is not the best name either.
Iteration
for index in range(len(str1)):
char = str1[index]
...
Using range(len(...)
in a for
loop is frowned upon in polite Python circles. If index
is required in the body of the loop, enumerate(...)
is preferred:
for index, char in enumerate(str1):
...
Special cases
elif index == len(str1) - 1
is executed on every non-space iteration of the loop. If your string is very, very long, this could be a source of inefficiency. It is testing for the end of the string, which happens at the end of the loop. Why not move this end-of-loop code out of the loop?
for index in range(len(str1)):
...
if char == " ":
...
else:
temp += char
if temp != "":
if final_str != "":
final_str = temp + " " + final_str
else:
final_str = temp
Iteration (reprise)
By removing the index == len(str1) - 1
test in the loop body, we find we no longer need the index
variable at all, so enumerate(...)
is unnecessary, and the for
loop can be simplified further:
for char in sentence:
...
Special cases (reprise)
Your code handles (and my above modification) has to handle the special case of a single word separately from multiple words. The reason is words end both with a subsequent space AND at the end of the string. We could work around this by intentionally adding a space at the end of the string ourselves, before processing begins.
str1 += " "
This additional sentinel guarantees words will always end with a space, and simplifies the code in the loop. Minor additional processing at the end may be necessary to remove the extra space in the output, depending on the exact implementation.