8

I have an array of bools and now I want to swap those entries for numbers.

False => 0
True => 1

I have written two different pieces of code and I would like to know, which one is better and why. This is not so much about actually solving the problem, as about learning.

arr = [[True,False],[False,True],[True,True]]
for i,row in enumerate(arr):
 for j,entry in enumerate(row):
 if entry:
 arr[i][j] = 1
 else:
 arr[i][j] = 0
print(arr)

And the second approach:

arr = [[True,False],[False,True],[True,True]]
for i in range(len(arr)):
 for j in range(len(arr[i])):
 if arr[i][j]:
 arr[i][j] = 1
 else:
 arr[i][j] = 0 
print(arr)

I read that there are ways to do this with importing itertools or similar. I am really not a fan of importing things if it can be done with "on-board tools", but should I rather be using them for this problem?

asked Oct 31, 2015 at 0:21
2
  • 2
    Definitely option A; iterating over range(len(...)) isn't pythonic. Commented Oct 31, 2015 at 0:26
  • Thank you very much. That was the answer I was looking for ! Commented Oct 31, 2015 at 14:33

2 Answers 2

11

Let's define your array:

>>> arr = [[True,False],[False,True],[True,True]]

Now, let's convert the booleans to integer:

>>> [[int(i) for i in row] for row in arr]
[[1, 0], [0, 1], [1, 1]]

Alternatively, if we want to be more flexible about what gets substituted in, we can use a ternary statement:

>>> [[1 if i else 0 for i in row] for row in arr]
[[1, 0], [0, 1], [1, 1]]
answered Oct 31, 2015 at 0:28
Sign up to request clarification or add additional context in comments.

3 Comments

Beat me to it and much more elegant, I just did [(lambda x: [int(y) for y in x])(i) for i in foo] - I can't much say why my brain shutdown so hard and I didn't just do what you did :) end of the day on a friday must be
Maybe int(bool(i)) rather than the ternary?
John1024. Thank you very much for also adding in the last part. Because later on I might want to use some other symbols instead of 1 and 0 :D
3

If you want to stay with a for-loop (e.g. because you want to mutate the existing array instead of creating a new one), you should simplify the code.

I would first simplify the outer loop by removing the indexing (there is no need for it since it's even easier to modify a row than a nested array):

for row in arr:
 for j, entry in enumerate(row):
 if entry:
 row[j] = 1
 else:
 row[j] = 0

these kinds of simple if statement can often be simplified by using an if expression:

 row[j] = 1 if entry else 0

but in this case we can do even better. bool is a subclass of int (ie. all bool's are int's), and True and False are defined to be exactly 1 and 0 respectively -- if you scroll down to the specification section of PEP 285 (https://www.python.org/dev/peps/pep-0285/) you'll see that that equivalence is not accidental but very much by design.

We can therefore use the int constructor to grab the underlying integer values[*], since int(True) == 1 and int(False) == 0, the if-expression can be simplified to:

row[j] = int(entry)

[*] technically this is an explicit upcast to a base class, and not a conversion constructor..

The simplified code:

for row in arr:
 for j, entry in enumerate(row):
 row[j] = int(entry)
answered Oct 31, 2015 at 2:05

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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