0

Been trying to transition from Java to Python but I am having difficulty writing for loops that iterate through a string.
As you can see, I tried accessing each index to check its case. If that letter is capital then we lowercase it and vice versa.
I'm not really sure why it is returning an unchanged string if I am already making changes to that particular index

def swap_case(s):

    for x in range(len(s)):
        if s[x].isupper():
            s[x].lower() 
        if s[x].islower():
            s[x].upper()

    return s
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153

6 Answers6

4

If s is a string you can do the following:

def swap_case(s):
    return s.swapcase()

That being said, I don't think you need to create a function if that is all you are doing. You can just call .swapcase() on the string rather than passing it into a function.

NendoTaka
  • 1,224
  • 8
  • 14
1

In Python, strings are immutable. Therefore, you can use a list comprehension with .join:

def swap_case(s):
   return ''.join([i.lower() if i.isupper() else i.upper() for i in s])
Ajax1234
  • 69,937
  • 8
  • 61
  • 102
  • Strings are immutable, you can't assign to `s[x]`. – Barmar Nov 22 '17 at 21:58
  • @Barmar correct, however, the OP mentioned that he is iterating over a list, not a string. – Ajax1234 Nov 22 '17 at 21:59
  • You can remove the `[...]` and use a generator comprehension instead, which should be negligibly faster. – TemporalWolf Nov 22 '17 at 22:05
  • 1
    nit: i wouldn't use `i` for a character in a string. `i` is never anything but an index in my head. I'd prefer `c` or `ch`. (I mention mostly because when I skimmed this answer I thought "Hey you can't lowercase an index!") – Adam Smith Nov 22 '17 at 22:07
  • 1
    @TemporalWolf generally yes, however, in the case of `join`, it still has to format the passed generator to a list, so it is actually more efficient to pass a list. – Ajax1234 Nov 22 '17 at 22:09
1

For a recursive solution:

def swap_case(s):
    if not s:  # empty string
        return s
    head, tail = s[0], s[1:]
    if head.isupper():
        return head.lower() + swap_case(tail)
    else:
        return head.upper() + swap_case(tail)

This is not ideally performant in Python (which generally implements recursion poorly under the hood), but it's not all that bad for reasonably-sized strings.

Adam Smith
  • 52,157
  • 12
  • 73
  • 112
0

As the comments have mentioned, s[x].lower() returns a new string, and it can't be assigned to since strings are immutable. So you need to accumulate a new string.

def swap_case(s):
    s0 = ""
    for x in range(len(s)):
        if s[x].isupper():
            s0 += s[x].lower() 
        elif s[x].islower():
            s0 += s[x].upper()
    return s0

You can also iterate over it with a lambda, which will be more concise.

def swap_case(s):
    s0 = map(lambda x: x.lower() if x.isupper() else x.upper(), s)
    return ''.join(s0)
Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
0

In python you don't need to loop over strings like for x in range(len(s)). Instead python can be more succinct with for char in message. Furthermore the if clause looks like it should be followed by an elif and an else (for non alphabetical characters). The code below works well for short messages since += recopies the string each time due to it being an immutable type. If this impacts the speed of your program consider using str.join() instead.

def swap_case(message):
    swapped_message = ''
    for char in message:
        if char.isupper():
            swapped_message += char.lower()
        elif char.islower():
            swapped_message += char.upper()
        else:
            swapped_message += char
    return swapped_message
Matt Eding
  • 917
  • 1
  • 8
  • 15
  • 1
    Code only answers are not ideal. Please review [answer], then [edit] your answer, including things like *why does it not work the way OP tried* and *how this fixes it*. – TemporalWolf Nov 22 '17 at 22:06
0

See these 2 statements from your code:

s[x].lower()
s[x].upper()

s[x] is NOT this (as you may think):

+------+------+-----+------+-----+-------------+
| s[0] | s[1] | ... | s[x] | ... | s[len(s)-1] |
+------+------+-----+------+-----+-------------+
                      ^^^^

but the new 1-character string containing only the xth character from the original string s:

+------+------+-----+------+-----+-------------+
| s[0] | s[1] | ... | s[x] | ... | s[len(s)-1] |
+------+------+-----+------+-----+-------------+

                   copy of s[x] 
             (another place in the memory):
                    +------+
                    |      |
                    +------+
                      ^^^^

as it is not allowed to change characters in strings.

So you changed the case of that 1-character string, keeping your original string s unchanged.


Note:

s = "apple"
s = "orange"

is perfectly OK - the second statement didn't change "apple" into "orange" but it created the new string "orange" in an other place in the memory, and then labeled this new place with s (...which was originally the label of the string "apple").

MarianD
  • 13,096
  • 12
  • 42
  • 54