Swapping 1 with 0 and 0 with 1 in a Pythonic way
Asked Answered
J

18

69

In some part of my Python program I have a val variable that can be 1 or 0. If it's 1 I must change to 0, if it's 0 I must change to 1.

How do you do it in a Pythonic way?

if val == 1:
    val = 0
elif val == 0:
    val = 1

it's too long!

I did:

swap = {0: 1, 1:0}

So I can use it:

swap[val]

Other ideas?

Jezreel answered 22/11, 2009 at 17:10 Comment(4)
Is there a reason not to use True/False instead of 1/0 in your case?Coumas
The most Pythonic way to do this would take into account the meaning of the variable. Is it numeric? Boolean (i.e. True/False)? Does it have some semantic meaning that isn't obvious here? The mere fact that you want to toggle it implies that it has some meaning... what is it?Rosales
I think the term you're looking for is "toggle".Angus
I ended up using your swap solution because when I come back to this in years, it will immediately make sense to me. Also, it is extensible and customizable, in case I eventually need to work with more/different numbers.Paginal
I
262

This isn't pythonic, but it is language neutral. Often val = 1 - val is simplest.

Inexact answered 22/11, 2009 at 17:13 Comment(6)
That is clever, but it requires the person reading your code to think (probably), which may force you to have add a comment. I like the ternary better eg. val = 0 if val else 1 because it says exactly what it does.Amphimacer
Another way of saying the same thing: var=((var+1)&1).Upthrow
I guess I would just create a method called bit_flip and use the code in this answer. Once the name is there, it should be pretty easy to pick up what it does.Dorita
val = 1 - val in no way communicates val is always either 1 or 0 and that it is supposed to swap/flip these values. marked = not marked communicates both.Coumas
@J.F. Sebastien: The original poster didn't say why, but seemed to want a number and not a boolean so you'd have to do int(not val) to get exactly the same behaviour. I think that this was discussed on the comments to one of the other answers.Inexact
@CharlesBailey: True == 1 and False == 0 in Python. Arithmetic is the same; though you might see the difference if you call str(val). You don't need the exact int in many cases.Coumas
V
62

The shortest approach is using the bitwise operator XOR.

If you want val to be reassigned:

val ^= 1

If you do not want val to be reassigned:

val ^ 1
Visa answered 9/12, 2009 at 3:35 Comment(1)
I like this answer because it provides the opportunity to do the swap dynamically, using "^ 1" or "^ 0", with the latter leading to no swap.Lorollas
W
32

Since True == 1 and False == 0 in python,

you could just use var = not var

It will just swap it.

Wombat answered 22/11, 2009 at 17:13 Comment(9)
This seems an implementation detail and can't rely on it.Jezreel
but int(not 1) == 0 and int(not 0) == 1 because int(True) == 1 and int(False) == 0. and this one is likely not an implementation detail.Ancalin
bool is a subclass of int, and Alex Martelli uses sum([list of booleans] to count the number of True's, so I think it must be safe.Cyprinodont
The fact that 0 evalutes to false, and 1 to true in a boolean context are both guaranteed in python: docs.python.org/reference/expressions.html#boolean-operationsInexact
seems like telling var = not var is like parsing html with regex in SO? I can't believe that!Wombat
It's safe (and just fine!) if all you ever do with var is arithmetic (nothing to do with "parsing html with regex", which is just silly!-), but if you ever do a str(var) (including an intrinsic one e.g. in print), bool behaves differently (as a subclass, it overrides __str__). Not enough info in the question to make sure there's no such stringification, so 1 - var as in the selected answer is safer.Cero
It's safe but not expressive as prose, which is why i would suggest using the ternary (see my answer).Amphimacer
Coming from a background of digital/boolean logic, this approach seems the most clear, concise and readable.Angus
To address the concern noted by @AlexMartelli, I have submitted a derived answer that additionally uses int.Lorollas
C
20

Just another possibility:

i = (1, 0)[i]

This works well as long as i is positive, as dbr pointed out in the comments it doesn't work for i < 0.

Are you sure you don't want to use False and True? It sounds almost like it.

Custommade answered 22/11, 2009 at 18:23 Comment(2)
It wont error if i is -1 or -2, and would act strangely. {0: 1, 1:0}[i] would error howeverRomanic
@Romanic thanks. I wanted to include this in the answer, but then I saw that the OP had already found this answer. I'm sticking with the one I have because it's really compact.Ozellaozen
L
12

To expand upon the answer by "YOU", use:

int(not(val))

Examples:

>>> val = 0
>>> int(not(val))
1

>>> val = 1
>>> int(not(val))
0

Note that this answer is only meant to be descriptive, not prescriptive.

Lorollas answered 13/7, 2016 at 21:19 Comment(0)
A
8

In your case I recommend the ternary:

val = 0 if val else 1

If you had 2 variables to swap you could say:

(a, b) = (b, a)
Amphimacer answered 22/11, 2009 at 18:5 Comment(1)
OP doesn't have two values to swap. he has a single value that he wants to changeVaden
E
6

I have swapped 0s and 1s in a list.

Here's my list:

list1 = [1,0,0,1,0]

list1 = [i^1 for i in list1] 
#xor each element is the list

print(list1)

So the outcome is: [0,1,1,0,1]

Electrothermal answered 11/10, 2019 at 5:59 Comment(0)
P
4

Here's a simple way:

val = val + 1 - val * 2

For Example:

If val is 0

0+1-0*2=1

If val is 1

1+1-1*2=0
Philipines answered 14/10, 2020 at 13:42 Comment(1)
you could make it simpler : val = 1 - valExpectant
A
3

If you want to be short:

f = lambda val: 0 if val else 1

Then:

>>> f(0)
1
>>> f(1)
0
Artieartifact answered 22/11, 2009 at 17:19 Comment(0)
O
3

The most pythonic way would probably be

int(not val)

But a shorter way would be

-~-val
Ornithischian answered 21/5, 2017 at 2:41 Comment(0)
N
3

Another option:

val = (not val) * 1
Nubbly answered 8/8, 2021 at 17:40 Comment(0)
J
1

Just another way:

val = ~val + 2
Julianajuliane answered 6/5, 2015 at 10:53 Comment(0)
M
1

(0,1)[not val] flips the val from 0 to 1 and vice versa.

Murdock answered 5/8, 2015 at 22:39 Comment(1)
not val by itself flips the val from 0 to 1. Note: False == 0 and 1 == True in Python.Coumas
K
1

After seeing all these simpler answers i thought of adding an abstract one , it's Pythonic though :

val = set(range(0,2)).symmetric_difference(set(range(0 + val, val + 1))).pop()

All we do is return the difference of 2 sets namely [0, 1] and [val] where val is either 0 or 1.

we use symmetric_difference() to create the set [0, 1] - [val] and pop() to assign that value to variable val.

Kennie answered 22/5, 2018 at 15:12 Comment(2)
How is this Pythonic? From the Zen of Python: "readability counts"Schwing
young me discovered something new , decided to write about itKennie
U
0

Function with mutable argument. Calling the swaper() will return different value every time.

def swaper(x=[1]):
    x[0] ^= 1
    return x[0]
Unbind answered 24/3, 2014 at 19:3 Comment(0)
W
0

Your way works well!

What about:

val = abs(val - 1)

short and simple!

Wagstaff answered 29/11, 2016 at 18:47 Comment(1)
or val = 1 - valOrnithischian
D
0

use np.where

ex.

np.where(np.array(val)==0,1,0)

this gives 1 where val is 0 and gives 0 where val is anything else, in your case 1

EDIT: val has to be array

Deathless answered 11/12, 2018 at 1:19 Comment(0)
B
0

If you are using an array and it is in numpy you can use

>> y = np.array([1,0,1,1])
>> y^1
[0,1,0,0]
Bedder answered 23/2, 2023 at 9:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.