2

I'm trying to understand the replace method. I have a string of numbers where I would like to make some adjustments. Particularly, I would categorize the numbers based on a threshold:

def makeAdjustment(x):
    for each in x:
        if int(each) < 5:
            x = x.replace(each, "0")
        else:
            x = x.replace(each, "1")
    return x

In use:

>>> makeAdjustment("800857237867") == "100111001111" 
True
>>> makeAdjustment("15889923") == "01111100" 
True
>>> makeAdjustment("14963896") == "00110111" 
True

However, if the sequence of numbers gets larger the string is converted to zero:

>>> makeAdjustment("366058562030849490134388085")      
'000000000000000000000000000'
5
  • 3
    Think about it - after you've replaced all numbers above five with one, all numbers are below five. Commented Apr 17, 2017 at 8:14
  • The replace method returns a copy of the string with all occurrences of substring old replaced by new. So, eventually everything is becoming zero. Commented Apr 17, 2017 at 8:17
  • 1
    each is a number right? and replace replaces all numbers, not just the number at that position. Do you want it positional? Commented Apr 17, 2017 at 8:17
  • 1
    It may help to understand, if you print x for each step. Commented Apr 17, 2017 at 8:17
  • @m0nhawk what's with the antipathy for python-3.x? You even remove it from questions that specifically mention that version. Seems like a waste of time, given that you aren't fixing other obvious problems. Commented Apr 17, 2017 at 8:18

4 Answers 4

3

The issue here isn't that the string is larger, it's that instances of '1' or '0' shouldn't be replaced. When you encounter a '1' later on in the string (as in your last case) you'll replace all previous instances of '1' with '0'.

One solution is to special case them:

def makeAdjustment(x):
    for each in x:
        if int(each) in {'1', '0'}:
            continue
        if int(each) < 5:
            x = x.replace(each, "0", 1)
        else:
            x = x.replace(each, "1")
    return x

This is one option but it isn't the best since you're calling replace for every iteration. You can do much better by just using join here:

def makeAdjustment(x):
    return "".join("1" if int(i) > 5 else "0" for i in x)

which is cleaner, clearer and faster:

# for loop 
%timeit makeAdjustment("366058562030849490343880185")
10000 loops, best of 3: 39.1 µs per loop
# join
%timeit makeAdjustment("366058562030849490343880185")
100000 loops, best of 3: 17.7 µs per loop
Sign up to request clarification or add additional context in comments.

Comments

2

If you want to replace each character, build a new string character by character instead of using replace:

def makeAdjustment(x):
    result = []
    for each in x:
        if int(each) < 5:
            result.append("0")
        else:
            result.append("1")
    return ''.join(result)

or in short:

def makeAdjustment(x):
    return ''.join("0" if int(each) < 5 else "1" for each in x)

Comments

1

My way of doing it is just to turn it into a list and go by position. It's so much easier since replace is replacing All each characters no matter where the position Here we use each as an index to keep track of our location in the list

def makeAdjustment(x):
    x = list(x)
    for each in range(len(x)+1):
        if int(x[each]) < 5:
            x[each] = '0'
        else:
            x[each] = '1'
        #Turn it back into a string instead of a list 
        x = "".join(x)
        return x

Comments

1
def makeAdjustment(x):
    splitted = [c for c in enumerate(x)]
    for each in splitted:
        if int(each[1]) < 5:
            splitted[each[0]] = "0"
        else:
            splitted[each[0]] = "1"

    return "".join(splitted)

EDIT: The above code splits the string and makes a list of tuple where each character in the string is accompanied by index of it. This is done using enumerate.

The list (splitted) is enumerated where each[1] will contain the actual character from the string whereas each[0] will contain the index of the actual character in the given string.

Based on the value contained in each[1] the value contained at each[0] index of the splitted is modified.

In the end, the string is joined using "".join(splitted).

2 Comments

Could you maybe add a couple sentences explaining your solution? To many, just viewing code isn't helpful.
@JimFasarakisHilliard: I have added the explanation. Doesn't feel pythonic but gets the work done.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.