Steven's Homepage

Weekly Challenge 313 Task 1

Reverse Letters: improving memory efficiency

The following was my entry for the Weekly Challenge 313 Task 1[1].

#!/usr/bin/env python3


def reverse_letters(string):
    """ Given a string, reverse only the alphabetic characters in the string.

    >>> reverse_letters('p-er?l')
    'l-re?p'
    >>> reverse_letters('wee-k!L-y')
    'yLk-e!e-w'
    >>> reverse_letters('_c-!h_all-en!g_e')
    '_e-!g_nel-la!h_c'
    """
    alpha_reversed = reversed([c for c in string if c.isalpha()])
    return "".join(next(alpha_reversed) if c.isalpha() else c for c in string)


if __name__ == "__main__":
    import doctest

    doctest.testmod(verbose=True)

I was not 100% happy with this code because of the creation of an intermediate list for the call to reversed. At the time I couldn’t come up with a solution which would use a generator expression and therefore be more memory efficent.

While reviewing other peoples Python solutions I saw someone reverse the initial string using string[::-1] which I liked but later found out this is not memory efficent for large strings as it creates a new string.

Finally, I found that I could just call reversed(string), enabling me to iterate over the string in reverse order within a generator expression. My revised solution for the task looks like this:

def reverse_letters(string):
    alpha_iter = (c for c in reversed(string) if c.isalpha())
    return "".join(next(alpha_iter) if c.isalpha() else c for c in string)

References

  1. The Weekly Challenge - 313 Task 2: Reverse Letters