ApuCoder
ApuCoder

Reputation: 2898

How to distinguish between 1 and True (equivalently, 0 and False)?

The following code block raises the aforementioned question:

L1 = [1, True, 0, False]*5
L2 = [True, 1, False, 0]*5
D1 = dict(zip(L1, range(len(L1))))
D2 = dict(zip(L2, range(len(L2))))


print(L1) # [1, True, 0, False, 1, True, 0, False, 1, True, 0, False, 1, True, 0, False, 1, True, 0, False]
print(D1) # {1: 17, 0: 19}
print(L2) # [True, 1, False, 0, True, 1, False, 0, True, 1, False, 0, True, 1, False, 0, True, 1, False, 0]
print(D2) # {True: 17, False: 19}

#print(True in D1)
#print(0 in D2)
#print(True == 1)
#print(False == 0)

I can understand that being a subclass of int this is the expected behavior of bool. But does that not affect the structure of list?

How can I handle their (1 and 0 or True and False) explicit presence in any case? i.e. I want something like: {1 : 16, True : 17, 0 : 18, False : 19} (in case of D1), in a pure pythonic way.

Upvotes: 1

Views: 210

Answers (1)

Tomerikoo
Tomerikoo

Reputation: 19414

Gathering ideas from the comments* to an answer:


You seem to be aware of it, but the reason this happens is because True == 1 and False == 0. This means that as dict keys they will be mapped as equal and there can be no repeating keys.

To overcome this:

  1. You could convert the keys to strings:

    L1 = [1, True, 0, False]*5
    D1 = dict(zip(map(str, L1), range(len(L1))))
    
    print(D1)
    

    Will give:

    {'1': 16, 'True': 17, '0': 18, 'False': 19}
    

    But this has the downside of not being able to to actually tell the type of the key. You could overcome this by using ast.literal_eval when reading the dict:

    import ast
    
    for key, value in D1.items():
        key = ast.literal_eval(key)
        print(key, type(key))
    

    Will give:

    1 <class 'int'>
    True <class 'bool'>
    0 <class 'int'>
    False <class 'bool'>
    

  1. Change the keys of the dict to be tuples of the value and its type:

    L1 = [1, True, 0, False]*5
    D1 = dict(zip(zip(L1, [type(x) for x in L1]), range(len(L1))))
    
    print(D1)
    

    Will give:

    {(1, <class 'int'>): 16, (True, <class 'bool'>): 17, (0, <class 'int'>): 18, (False, <class 'bool'>): 19}
    

    And when reading the dict you can get the 0-index element of the keys to get the actual real value.


* converting to string idea by CozyCode. Adding the type to the key idea by VPfB

Upvotes: 1

Related Questions