-3

I am using Python and having trouble because of 'String formatting' error.

x = int(input())
x_list = ' '.join(str(x)).split()
for i in range(len(x_list)):
    if x_list[i] % 2 == 0  and x_list[i+1] % 2 == 0 :
        x_list.insert(i+1,'*')

x_list is an arbitrary list that I made, and the error occurs at the 4th line. I think the error occurs because of the '%', which I wanted to use to calculate the remainder.

How can I solve this problem?

rioV8
  • 24,506
  • 3
  • 32
  • 49
  • Does x_list contain strings? Maybe Pyhon interprets the % sign as a directive to format string at `x_list[i] % 2`, in similar to this example `'Hello, %s' % name`. – Aviv Yaniv Aug 27 '20 at 07:58
  • 1
    Please post more context of your code. – Josef Aug 27 '20 at 07:59
  • I edited my code. – Jongmin Lee Aug 27 '20 at 08:01
  • 2
    `x_list` is not an *arbitrary* list, it is a list of strings. Either convert the whole list back to ints, or just surround each get `int(x_list[i]) % 2` – Tomerikoo Aug 27 '20 at 08:03
  • 1
    use a debugger and see what the result of each line is. You make fundamental errors. and read the docs about all functions you use – rioV8 Aug 27 '20 at 08:03
  • `x_list[i]` is a string. So how do you imagine `x_list[i] % 2 == 0` working? – khelwood Aug 27 '20 at 08:04
  • I changed x_list as 'x_list = list(map(int, ' '.join(str(x)).split()))', but the error keeps going on. – Jongmin Lee Aug 27 '20 at 08:05
  • The same error? I don't think so... Probably an IndexError and that because it needs to be `for i in range(len(x_list)-1):` because you read 2 items each loop – Tomerikoo Aug 27 '20 at 08:07
  • @JongminLee Thats because you insert a string manually again into this int list, so the error will inevitably happen again, you need to use seperate lists. – Josef Aug 27 '20 at 08:28

5 Answers5

1

Warning Note

Modifying list while looping on it is not preferable.


Some Explanation

What happens is that the line x_list[i] % 2 is interpreted as a directive to format string, as originally x_list contains strings.

Formatting with % is deprecated currently, on Python 3, however, you can read more here.


Mitigations

Note: This solves the formatting error, other logical errors that related to functionality may still exist.

x = int('12234')
x_list = ' '.join(str(x)).split()
# Going from indices 0...(N-1) as we use (i+1) each iteration
for i in range(len(x_list)-1):
    # Validating current and next are not invalid char '*'
    if '*' in [x_list[i], x_list[i+1]]:
        continue
    if int(x_list[i])% 2 == 0  and int(x_list[i+1])% 2 == 0 :
        x_list.insert(i+1,'*')

# ['1', '2', '*', '2', '3', '4']
print(x_list)
Aviv Yaniv
  • 6,188
  • 3
  • 7
  • 22
  • Some clarification for the "don't modify list while you are looping it" in this case. If you have more than two even numbers in a row in the list, it will fail as it will then try and multiply * with a number. – en_lorithai Aug 27 '20 at 08:11
  • Thank you @en_lorithai for the comment. Added clarification regarding the mitigations, it's just for the code not to raise formatting exception. There are logical flaws at the original code, therefore on code based on it. – Aviv Yaniv Aug 27 '20 at 08:17
1

If your x_list contains strings then you quite obviously cannot calculate the remainder of that string divided by 2.

Also, even if your x_list only contains numbers, you could encounter an IndexError, since in your last iteration x_list[i+1] could be out of bounds.

You are also modifying the same list as you are looping over it, which is generally undesirable.

WTomas
  • 51
  • 4
1

You're getting a string formatting issue because you're inserting a string '*' into the list you're iterating through already, at one index down from i. You can't have a string perform modulo operations. Not entirely sure what you are trying to do there, but what you're seeing is normal behavior.

Also, the way your code currently works, you won't reach all of the integers in your original list.

EDIT: Responding to your edit:

x_list = ' '.join(str(x)).split()
for i in range(len(x_list)):
    if x_list[i] != '*':
        if (int(x_list[i]) % 2 == 0)  and (int(x_list[i+1]) % 2 == 0):
            x_list.insert(i+1,'*')

Just change your strings to int and check if the value at i is '*' or not

Jim Zhou
  • 311
  • 1
  • 10
  • You are right but the problem is even before the `*`. The initial list itself is consisted of strings representing numbers, not ints... – Tomerikoo Aug 27 '20 at 08:09
0

The way you convert str into list of chars is not correct and can be easily replaced by list(string). If you want to check all chars to be valid digits you can add str.isdecimal().

You're trying to modify list you're iterating over, which is also a mistake. Modifying source inside loop would break logic of loop, as a result some elements could be processed several times or skipped.

Finally you're trying to apply modulo (which is numeric operation) on str. To let it work as you expected you should cast element to int using int(string).

Edited code:

x = input()
if x.isdecimal():
    x_list = list(x)
    new_list = []
    for i in range(len(x_list) - 1):
        new_list.append(x_list[i])
        if not (int(x_list[i]) % 2 and int(x_list[i + 1]) % 2):
            new_list.append("*")
Olvin Roght
  • 7,677
  • 2
  • 16
  • 35
0
x = input()
x_list = ' '.join(str(x)).split()
for i in range(len(x_list)):
    try:
        if not(int(x_list[i]) % 2 and int(x_list[i+1]) % 2):
            x_list.insert(i+1,'*')
    except:
        continue

print(x_list)

Try this, it may work. idk what the output should be like "because you didn't mention it". but i tried to type the same code with some changes to avoid the error

AM Z
  • 423
  • 2
  • 9
  • Have you tried to research what exactly cause an error? – Olvin Roght Aug 27 '20 at 10:38
  • @OlvinRoght what causes an error is two things, the first is when he tried to do "%2" on a string (num). and the second error occur when he tried to do "%2" on the actual "string" operator, which is '*'. – AM Z Aug 27 '20 at 11:01
  • So why have you decided to handle exception instead of preventing it? – Olvin Roght Aug 27 '20 at 11:34
  • @OlvinRoght The exception just to prevent the string operator '*', because even if i type an if statement it'll work but it would be something like `if x_list[i] != '*' and x_list[i+1] != '*'` which is not legal because it won't be true 'never', just try it. I've try it already and it didn't work. EDIT: If you type an if statement like this `if x_list[i] != '*'` it'll give you an error, because inside the if statement he's using `x_list[i] and x_list[i+1]`, and ofc the `x_list[i+1]` will be `*` in a way or another. – AM Z Aug 27 '20 at 11:45
  • Even if you add 2 additional conditions *(which is ofc possible)* it will be another way of handling exception. I wanted to point you that you're inserting item into a list which you're currently processing in same loop, that's the main mistake. – Olvin Roght Aug 27 '20 at 12:00