2

I have a list storing variables. These variables store float numbers. For part of the program I am making, if a value has .0 at the end, I need to remove it and if not, it can stay the same.

For example: 2.0 would become 2 3.5 would stay as 3.5

Now the issue is later on in the program I need to sort and round the same set of numbers up and down. The question would be too long if I included all of the reasoning for as to why this is.

The code I have currently is as follows:

AddRatio=0.35
SubRatio=0.2
MultiRatio=0.2
DiviRatio=0.2
MoneyRatio=0.25

num_add_qs=10*AddRatio
num_sub_qs=10*SubRatio
num_multi_qs=10*MultiRatio
num_divi_qs=10*DiviRatio
num_money_qs=10*MoneyRatio

NumQs = [num_add_qs, num_sub_qs, num_multi_qs, num_divi_qs, num_money_qs]

for i in range(0,len(NumQs)):
    if isinstance(NumQs[i], float) == True:
        NumQs[i]=str(NumQs[i])
        if NumQs[i][2]=="0":
            NumQs[i]=NumQs[i][0:1]
            NumQs[i]=int(NumQs[i])
        else:
            NumQs[i]=float(NumQs[i])
            i=i+1

If I

print(NumQs) 

it returns

[3.5, 2, 2, 2, 2.5]

which are the results I want.

The issue is the actual value of the variable isn't changed. If I:

print(num_add_qs, num_sub_qs, num_multi_qs, num_divi_qs, num_money_qs)

The result is:

3.5 2.0 2.0 2.0 2.5

The variables need to be stored as integers if whole integers and floats if not. I convert them to strings purely to remove the .0 if relevant.

Where am I going wrong?

Wardy
  • 59
  • 1
  • 10

2 Answers2

3

There are a couple of things that I would improve with your current code:

  • Don't use isinstance, instead use: x == int(x).
  • Never use lots of individual similar/linked variables, either store them all in a list (as you are) and forget about the variables or better use a dictionary.

So, taking the dictionary approach, here is what we get:

AddRatio=0.35
SubRatio=0.2
MultiRatio=0.2
DiviRatio=0.2
MoneyRatio=0.25

num_add_qs=10*AddRatio
num_sub_qs=10*SubRatio
num_multi_qs=10*MultiRatio
num_divi_qs=10*DiviRatio
num_money_qs=10*MoneyRatio

num_dict = {'add': 10*AddRatio, 'sub': 10*SubRatio, 'multi': 10*MultiRatio, \
            'divi': 10*DiviRatio, 'money': 10*MoneyRatio}

num_dict = {k: int(v) if v == int(v) else v for k, v in num_dict.items()}

# --> {'sub': 2, 'multi': 2, 'money': 2.5, 'add': 3.5, 'divi': 2}

So, as to answer your comment about how the dictionary comprehension works, here's my best explanation - through the interpreter as examples speak more than words:

>>> int(1.0) if 1.0 == int(1.0) else 1.0
1
>>> int(1.6) if 1.6 == int(1.6) else 1.6
1.6
>>> d = {'a': 1.0, 'b': 2.5, 'c': 3}
>>> d.items()
dict_items([('c', 3), ('a', 1.0), ('b', 2.5)])
>>> for k, v in d.items():
...     print("k: {}, v: {}".format(k, v))
... 
k: c, v: 3
k: a, v: 1.0
k: b, v: 2.5
>>> {i: i+2 for i in range(8)}
{0: 2, 1: 3, 2: 4, 3: 5, 4: 6, 5: 7, 6: 8, 7: 9}
>>> {k: int(v) if v == int(v) else v for k, v in d.items()}
{'c': 3, 'a': 1, 'b': 2.5}
Joe Iddon
  • 20,101
  • 7
  • 33
  • 54
  • That list comprehension is pretty neat. I'm learning how to do those and that's a fun one to"unpack". (..it's still a "list comprehension" even if it's used like a dictionary, yeah? Not called a "dictionary comprehension") – BruceWayne Jan 13 '18 at 15:02
  • 1
    @BruceWayne Nope! It's called a dictionary comprehension :) – Joe Iddon Jan 13 '18 at 15:58
  • Could you briefly explain how num_dict = {k: int(v) if v == int(v) else v for k, v in num_dict.items()} works? Thanks :) – Wardy Jan 14 '18 at 17:21
1

When you initialize the list with those variables, you are making a list with copies of the values in those variables. From that point forward, there exist two entirely separate sets of values: those assigned to your original variables such as AddRatio and SubRatio, and those in the list.

Basically, if you want to change the values of those variables, you need to mutate those variables. Mutating the list will only change the values contained in the list. If I write:

val1 = 1
val2 = 2
list = [val1, val2]

I get a list that looks like this:

[1, 2]

The list is now an entirely separate object, and it has its own 1 and 2, if you will. Even if I change val like this:

val1 = 4

My list is still:

[1, 2]

And conversely, even if I change the list at index 0, val1 will not change.

That said, this behavior only holds true for primitive/immutable types in Python, like ints or lambdas. If you start copying complex objects, you run into issues of "deep" vs "shallow" copies (see here). The important thing to understand is that primitives are "pass by copy" whereas objects are "pass by reference". This difference is explained well here.

Mindful
  • 394
  • 3
  • 13