0
def reverse_words(text):
    return " ".join([x[::-1] for x in text.split(" ")])

I'm a little confused on the difference between the list comprehension and the for loop here.

for x in text.split(" "):
    return " ".join(x[::-1])

I thought these two would be the same, but they have different outputs. Can someone explain why?

  • 2
    In the first code you return the results after the loop is done, in the second code you return after the first iteration. – Guy Jul 04 '22 at 04:35
  • 1
    In the first one you're creating a list and then you return it. In the second one, you just return a value calculated in the first iteration. The return statement terminates the function, in that sense it's similar to `break`. – Ignatius Reilly Jul 04 '22 at 04:36
  • You would get the same results if, in the second case, you were to create a list, and append the result of each iteration before returning it. – Ignatius Reilly Jul 04 '22 at 04:38
  • Aside from the problem of [putting `return` inside a loop](https://stackoverflow.com/questions/44564414), the list comprehension version has the `' '.join` logic *outside* the list comprehension, *operating on* the resulting list. That's clearly different from the attempted `for` loop. – Karl Knechtel Jul 04 '22 at 09:33

1 Answers1

2

First, expand the list comprehension to a normal looking loop

From:

def reverse_words(text):
    return " ".join([x[::-1] for x in text.split(" ")])

to

def reverse_word(text):
    output_list = []
    for x in text.split(" "):
        output_list.append(x[::-1])
    return " ".join(output_list)

Then lets take a closer look at the "weird lines", e.g. x[::-1].

What is x[::-1]?

This is a short cut for reversing a list item, e.g.

>>> x = [1,2,3,4,5]
>>> x[::-1]
[5, 4, 3, 2, 1]

Now in string type:

>>> x = "abcde"
>>> x[::-1]
'edcba'

For more details, see

We have this weird text.split(" ")

Usually this is use in NLP (natural language processing) task to split a sentence into words, aka word tokenization e.g.

>>> text = "This is a sentence"
>>> text.split(" ")
['This', 'is', 'a', 'sentence']

So text.split(" ") returns "individual words" roughly (there are many nuance with "word tokenization" so str.split(" ") would be the simplest for English texts).

Combining text.split(" ") with x[::1]

Lets use some more sensible variable name than x here, essentially we are doing this:

# Word tokenization, so "abc def" -> ["abc", "def"]
for word in text.split(" "): 
    # Reverse each word, so "abc" -> "cba"
    print(word[::-1])

And what's with this last part on " ".join(...)?

str.join is a function from https://docs.python.org/3/library/stdtypes.html#str.join; its function is to join the items in a list with some str that you desire.

Here's some example:

>>> list_of_words = ["abc", "def", "xyz"]
>>> type(list_of_words)
<class 'list'>

>>> " ".join(list_of_words)
'abc def xyz'

>>> "-".join(list_of_words)
'abc-def-xyz'

>>> "-haha-".join(list_of_words)
'abc-haha-def-haha-xyz'

>>> output = " ".join(list_of_words)
>>> type(output)
<class 'str'>

Putting it all together, and expanding the list comprehension

We get this:

def reverse_words_in_text(text):
    # Keep a list of the reversed words.
    output_list_of_words = []

    # Word tokenization, so "abc def" -> ["abc", "def"]
    for word in text.split(" "): 
        # Reverse each word, so "abc" -> "cba"
        output_list_of_words.append(word[::-1])

    # Join back the tokens into a string.
    return " ".join(output_list_of_words)

Bonus: Can we avoid list comprehension totally for this function?

If you like one liner:

>>> reverse_words = lambda text: " ".join(text[::-1].split()[::-1]) 
>>> reverse_words('abc def ghi')
'cba fed ihg'

But that just makes the code even more unreadable.

alvas
  • 115,346
  • 109
  • 446
  • 738
  • 1
    Thanks for helping me understand and be very thorough about it. I really appreciate you laying it all out there. – fullmetal04 Jul 04 '22 at 16:52