Swap float values only using tuples [duplicate] - python

In Python, I've seen two variable values swapped using this syntax:
left, right = right, left
Is this considered the standard way to swap two variable values or is there some other means by which two variables are by convention most usually swapped?

Python evaluates expressions from left to right. Notice that while
evaluating an assignment, the right-hand side is evaluated before the
left-hand side.
Python docs: Evaluation order
That means the following for the expression a,b = b,a :
The right-hand side b,a is evaluated, that is to say, a tuple of two elements is created in the memory. The two elements are the objects designated by the identifiers b and a, that were existing before the instruction is encountered during the execution of the program.
Just after the creation of this tuple, no assignment of this tuple object has still been made, but it doesn't matter, Python internally knows where it is.
Then, the left-hand side is evaluated, that is to say, the tuple is assigned to the left-hand side.
As the left-hand side is composed of two identifiers, the tuple is unpacked in order that the first identifier a be assigned to the first element of the tuple (which is the object that was formerly b before the swap because it had name b)
and the second identifier b is assigned to the second element of the tuple (which is the object that was formerly a before the swap because its identifiers was a)
This mechanism has effectively swapped the objects assigned to the identifiers a and b
So, to answer your question: YES, it's the standard way to swap two identifiers on two objects.
By the way, the objects are not variables, they are objects.

That is the standard way to swap two variables, yes.

I know three ways to swap variables, but a, b = b, a is the simplest. There is
XOR (for integers)
x = x ^ y
y = y ^ x
x = x ^ y
Or concisely,
x ^= y
y ^= x
x ^= y
Temporary variable
w = x
x = y
y = w
del w
Tuple swap
x, y = y, x

I would not say it is a standard way to swap because it will cause some unexpected errors.
nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i]
nums[i] will be modified first and then affect the second variable nums[nums[i] - 1].

Does not work for multidimensional arrays, because references are used here.
import numpy as np
# swaps
data = np.random.random(2)
print(data)
data[0], data[1] = data[1], data[0]
print(data)
# does not swap
data = np.random.random((2, 2))
print(data)
data[0], data[1] = data[1], data[0]
print(data)
See also Swap slices of Numpy arrays

To get around the problems explained by eyquem, you could use the copy module to return a tuple containing (reversed) copies of the values, via a function:
from copy import copy
def swapper(x, y):
return (copy(y), copy(x))
Same function as a lambda:
swapper = lambda x, y: (copy(y), copy(x))
Then, assign those to the desired names, like this:
x, y = swapper(y, x)
NOTE: if you wanted to you could import/use deepcopy instead of copy.

That syntax is a standard way to swap variables. However, we need to be careful of the order when dealing with elements that are modified and then used in subsequent storage elements of the swap.
Using arrays with a direct index is fine. For example:
def swap_indexes(A, i1, i2):
A[i1], A[i2] = A[i2], A[i1]
print('A[i1]=', A[i1], 'A[i2]=', A[i2])
return A
A = [0, 1, 2, 3, 4]
print('For A=', A)
print('swap indexes 1, 3:', swap_indexes(A, 1, 3))
Gives us:
('For A=', [0, 1, 2, 3, 4])
('A[i1]=', 3, 'A[i2]=', 1)
('swap indexes 1, 3:', [0, 3, 2, 1, 4])
However, if we change the left first element and use it in the left second element as an index, this causes a bad swap.
def good_swap(P, i2):
j = P[i2]
#Below is correct, because P[i2] is modified after it is used in P[P[i2]]
print('Before: P[i2]=', P[i2], 'P[P[i2]]=', P[j])
P[P[i2]], P[i2] = P[i2], P[P[i2]]
print('Good swap: After P[i2]=', P[i2], 'P[P[i2]]=', P[j])
return P
def bad_swap(P, i2):
j = P[i2]
#Below is wrong, because P[i2] is modified and then used in P[P[i2]]
print('Before: P[i2]=', P[i2], 'P[P[i2]]=', P[j])
P[i2], P[P[i2]] = P[P[i2]], P[i2]
print('Bad swap: After P[i2]=', P[i2], 'P[P[i2]]=', P[j])
return P
P = [1, 2, 3, 4, 5]
print('For P=', P)
print('good swap with index 2:', good_swap(P, 2))
print('------')
P = [1, 2, 3, 4, 5]
print('bad swap with index 2:', bad_swap(P, 2))
('For P=', [1, 2, 3, 4, 5])
('Before: P[i2]=', 3, 'P[P[i2]]=', 4)
('Good swap: After P[i2]=', 4, 'P[P[i2]]=', 3)
('good swap with index 2:', [1, 2, 4, 3, 5])
('Before: P[i2]=', 3, 'P[P[i2]]=', 4)
('Bad swap: After P[i2]=', 4, 'P[P[i2]]=', 4)
('bad swap with index 2:', [1, 2, 4, 4, 3])
The bad swap is incorrect because P[i2] is 3 and we expect P[P[i2]] to be P[3]. However, P[i2] is changed to 4 first, so the subsequent P[P[i2]] becomes P[4], which overwrites the 4th element rather than the 3rd element.
The above scenario is used in permutations. A simpler good swap and bad swap would be:
#good swap:
P[j], j = j, P[j]
#bad swap:
j, P[j] = P[j], j

You can combine tuple and XOR swaps: x, y = x ^ x ^ y, x ^ y ^ y
x, y = 10, 20
print('Before swapping: x = %s, y = %s '%(x,y))
x, y = x ^ x ^ y, x ^ y ^ y
print('After swapping: x = %s, y = %s '%(x,y))
or
x, y = 10, 20
print('Before swapping: x = %s, y = %s '%(x,y))
print('After swapping: x = %s, y = %s '%(x ^ x ^ y, x ^ y ^ y))
Using lambda:
x, y = 10, 20
print('Before swapping: x = %s, y = %s' % (x, y))
swapper = lambda x, y : ((x ^ x ^ y), (x ^ y ^ y))
print('After swapping: x = %s, y = %s ' % swapper(x, y))
Output:
Before swapping: x = 10 , y = 20
After swapping: x = 20 , y = 10

Related

Project Euler Problem 2 in Python with Error Message

I am a complete beginner in coding and was trying problems from Project Euler in Python. Could anyone please explain what is wrong with my code?
Problem: Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
a = []
x = 1
y = 2
for y in range (1, 400000):
if x % 2:
a.append(x)
x = y, y = x + y
print(sum(a))
I received the error message "cannot unpack non-iterable int object". What does this message mean and how to avoid it?
You get that error because you have the line x = y, y = x + y which is interpreted as an attempt to unpack values from an iterable into y, y, so you need to have a new line between x = y and y = x + y.
However since x is assigned with the value of y before y is updated, the better option is to change the line to x, y = y, x + yas JackTheCrab suggested in a comment.
Look the below example as well to explain the error:
price, amount = ["10$", 15] #iterable that can be unpacked
price, amount = 15 # this is just an int and this row will throw error "Cannot unpack non-iterable int object"
x = y, y = x + y
When i take away the addition from the end and the assignment from the beginning, the error still is there.
y, y = x
Output : an error. about non-iterable int ! Because you can unpack an iterable.
iterable = [0, 1, 2]
zero = iterable[0]
one = iterable[1]
two = iterable[2]
is not very good (sorry for my bad english ...) to use, because you have to type iterable[n] again and again. That's why you can unpack such iterables like this:
iterable = [0, 1, 2]
zero, one, two = iterable
This will produce the same result as the above long version.
Back to your code,
x = y, y = x + y
the python interpreter will first work on the assignment (x = ...). To resolve it, it tries to unpack x + y into two values, but this is not possible of course.
To declare two variables on one line, you have to separate the assignments with a colon ;, not a comma. But when you do just that, x will have the same value as y at the beginning, and so y will then be the double of itself, which surely is not what you wanted. Maybe you should do it like this ?
a = []
x = 1
y = 2
for y in range (1, 400000):
if x % 2:
a.append(x)
x, y = y, x + y
# above is equivalent to
# temp = y
# y = x + y
# x = temp
print(sum(a))

How to add a constraint which requires an integer variable belongs to an array?

Suppose I have a z3py integer variable x = Int('x'), and an integer array a = [1, 2, 3]. Then I add a constraint through s.add(x in a).
I think this is satisfiable because x can be 1 or 2 or 3. But it's unsitisfiable actually. Can anyone tell me how can I add a constraint to make sure x in a?
Thanks!
Here is the python code I used. I thought the output answer would be s is satisfiable, because x can be equal to 1 or 2 or 3, then the constraint x in a is satisfied. But the answer is actually unsat. Maybe this is not the right method to specify this constraint. So my question is how to specify such a constraint to make sure a variable can only be instantiated with the value in a specific array.
from z3 import *
x = Int('x')
a = [1, 2, 3]
s = Solver()
s.add(x in a)
print(s.check())
This should do:
from z3 import *
a = [1,2,3]
s = Solver()
x = Int('x')
s.add(Or([x == i for i in a]))
# Enumerate all possible solutions:
while True:
r = s.check()
if r == sat:
m = s.model()
print m
s.add(x != m[x])
else:
print r
break
When I run this, I get:
[x = 1]
[x = 2]
[x = 3]
unsat
"x in a" is a python expression, that evaluates to False before you assert the constraint, since the variable x does not belong to the array.
One method is to build an z3.And or z3.Or constraint using a loop
# Finds all numbers in the domain, for which it's square is also in the domain
import z3
exclude = [1,2]
domain = list(range(128))
number = z3.Int('number')
squared = number * number
solver = z3.Solver()
solver.add(z3.Or([ number == value for value in domain ]))
solver.add(z3.Or([ squared == value for value in domain ]))
solver.add(z3.And([ number != value for value in exclude ]))
solver.add(z3.And([ squared != value for value in exclude ]))
solver.push() # create stack savepoint
output = []
while solver.check() == z3.sat:
value = solver.model()[number].as_long()
solver.add( number != value )
output.append(value)
solver.pop() # reset stack to last solver.push()
print(output)
# [10, 0, 4, 6, 5, 11, 9, 8, 3, 7]
print(sorted(output))
# [0, 3, 4, 5, 6, 7, 8, 9, 10, 11]

Why are lists created by a function not iterable

I'm new to python and don't understand much. I created a function that takes a number and puts all the integers which lead up to that number, including that number, into a list. Or so I thought, turns out I cant actually use the created list as a list. Any ideas on how I can make it useable?
def break_up(x):
"""breaks up the the integers adding up to a number x, starting at 1. Works for any positive number or 0"""
y = 1
b = 1
a = []
while y <= x:
n = x - x + b
b = b + 1
y = y + 1
a.append(n)
print(a)
As people have commented, your indentation is incorrect, but in addition you are not actually calling the function.
The function needs to return an object. An object created in a function stays there and is not visible outside (unless it is global) - this is called encapsulation and is an important programming technique which enables functions to be used anywhere.
Note that even the multi-line comment has to be indented (and I have made it multi-line)
Here is my version of your program:
def break_up(x):
"""
breaks up the the integers adding up to a number x, starting at 1.
Works for any positive number or 0
"""
y = 1
b = 1
a = []
while y <= x:
n = x - x + b
b = b + 1
y = y + 1
a.append(n)
return a # <<<< added
# At this point, the name 'a' is not visible
thing = break_up(5)
print(thing)
# or
print(break_up(5))
Just for fun, try this:
$ python3 -i gash.py
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
>>> help(break_up)

Order of execution of tuples in Python during assignment [duplicate]

What is the difference between the following Python expressions:
# First:
x,y = y,x+y
# Second:
x = y
y = x+y
First gives different results than Second.
e.g.,
First:
>>> x = 1
>>> y = 2
>>> x,y = y,x+y
>>> x
2
>>> y
3
Second:
>>> x = 1
>>> y = 2
>>> x = y
>>> y = x+y
>>> x
2
>>> y
4
y is 3 in First and 4 in Second
In an assignment statement, the right-hand side is always evaluated fully before doing the actual setting of variables. So,
x, y = y, x + y
evaluates y (let's call the result ham), evaluates x + y (call that spam), then sets x to ham and y to spam. I.e., it's like
ham = y
spam = x + y
x = ham
y = spam
By contrast,
x = y
y = x + y
sets x to y, then sets y to x (which == y) plus y, so it's equivalent to
x = y
y = y + y
It is explained in the docs in the section entitled "Evaluation order":
... while evaluating an assignment, the right-hand side is evaluated
before the left-hand side.
The first expression:
Creates a temporary tuple with value y,x+y
Assigned in to another temporary tuple
Extract the tuple to variables x and y
The second statement is actually two expressions, without the tuple usage.
The surprise is, the first expression is actually:
temp=x
x=y
y=temp+y
You can learn more about the usage of comma in "Parenthesized forms".
An observation regarding the left-hand side as well: the order of assignments is guaranteed to be the order of their appearance, in other words:
a, b = c, d
is equivalent functionally to precisely (besides t creation):
t = (c, d)
a = t[0] # done before 'b' assignment
b = t[1] # done after 'a' assignment
This matters in cases like object attribute assignment, e.g.:
class dummy:
def __init__(self): self.x = 0
a = dummy(); a_save = a
a.x, a = 5, dummy()
print(a_save.x, a.x) # prints "5 0" because above is equivalent to "a = dummy(); a_save = a; t = (5, dummy()); a.x = t[0]; a = t[1]"
a = dummy(); a_save = a
a, a.x = dummy(), 5
print(a_save.x, a.x) # prints "0 5" because above is equivalent to "a = dummy(); a_save = a; t = (dummy(), 5); a = t[0]; a.x = t[1]"
This also implies that you can do things like object creation and access using one-liners, e.g.:
class dummy:
def __init__(self): self.x = 0
# Create a = dummy() and assign 5 to a.x
a, a.x = dummy(), 5
I've recently started using Python and this "feature" baffled me. Although there are many answers given, I'll post my understanding anyway.
If I want to swap the values of two variables, in JavaScipt, I'd do the following:
var a = 0;
var b = 1;
var temp = a;
a = b;
b = temp;
I'd need a third variable to temporarily hold one of the values. A very straightforward swap wouldn't work, because both of the variables would end up with the same value.
var a = 0;
var b = 1;
a = b; // b = 1 => a = 1
b = a; // a = 1 => b = 1
Imagine having two different (red and blue) buckets and having two different liquids (water and oil) in them, respectively. Now, try to swap the buckets/liquids (water in blue, and oil in red bucket). You can't do it unless you have an extra bucket.
Python deals with this with a "cleaner" way/solution: Tuple Assignment.
a = 0
b = 1
print(a, b) # 0 1
# temp = a
# a = b
# b = temp
a, b = b, a # values are swapped
print(a, b) # 1 0
I guess, this way Python is creating the "temp" variables automatically and we don't have to worry about them.
In the second case, you assign x+y to x
In the first case, the second result (x+y) is assigned to y
This is why you obtain different results.
After your edit
This happen because, in the statement
x,y = y,x+y
all variables at the right member are evaluated and, then, are stored in the left members. So first proceed with right member, and second with the left member.
In the second statement
x = y
y = x + y
yo first evaluated y and assign it to x; in that way, the sum of x+y is equivalent to a sum of y+y and not of x+x wich is the first case.
The first one is a tuple-like assignment:
x,y = y,x+y
Where x is the first element of the tuple, and y is the second element, thus what you are doing is:
x = y
y = x+y
Wheras the second is doing a straight assign:
x=y
x=x+y
Other answers have already explained how it works, but I want to add a really concrete example.
x = 1
y = 2
x, y = y, x+y
In the last line, first the names are dereferenced like this:
x, y = 2, 1+2
Then the expression is evaluated:
x, y = 2, 3
Then the tuples are expanded and then the assignment happens, equivalent to:
x = 2; y = 3
For newbies, I came across this example that can help explain this:
# Fibonacci series:
# the sum of two elements defines the next
a, b = 0, 1
while a < 10:
print(a)
a, b = b, a+b
With the multiple assignment, set initial values as a=0, b=1.
In the while loop, both elements are assigned new values (hence called 'multiple' assignment). View it as (a,b) = (b,a+b). So a = b, b = a+b at each iteration of the loop. This continues while a<10.
RESULTS:
0
1
1
2
3
5
8
Let's grok the difference.
x, y = y, x + y
It's x tuple xssignment, mexns (x, y) = (y, x + y), just like (x, y) = (y, x)
Stxrt from x quick example:
x, y = 0, 1
#equivxlent to
(x, y) = (0, 1)
#implement xs
x = 0
y = 1
When comes to (x, y) = (y, x + y)
ExFP, have x try directly
x, y = 0, 1
x = y #x=y=1
y = x + y #y=1+1
#output
In [87]: x
Out[87]: 1
In [88]: y
Out[88]: 2
However,
In [93]: x, y = y, x+y
In [94]: x
Out[94]: 3
In [95]: y
Out[95]: 5
The result is different from the first try.
Thx's because Python firstly evaluates the right-hand x+y
So it equivxlent to:
old_x = x
old_y = y
c = old_x + old_y
x = old_y
y = c
In summary, x, y = y, x+y means,
x exchanges to get old_value of y,
y exchanges to get the sum of old value x and old value y,
a, b = 0, 1
while b < 10:
print(b)
a, b = b, a+b
Output
1
1
2
3
5
8
the variables a and b simultaneously get the new values 0 and 1, the same a, b = b, a+b, a and b are assigned simultaneously.

Multiple assignment and evaluation order in Python

What is the difference between the following Python expressions:
# First:
x,y = y,x+y
# Second:
x = y
y = x+y
First gives different results than Second.
e.g.,
First:
>>> x = 1
>>> y = 2
>>> x,y = y,x+y
>>> x
2
>>> y
3
Second:
>>> x = 1
>>> y = 2
>>> x = y
>>> y = x+y
>>> x
2
>>> y
4
y is 3 in First and 4 in Second
In an assignment statement, the right-hand side is always evaluated fully before doing the actual setting of variables. So,
x, y = y, x + y
evaluates y (let's call the result ham), evaluates x + y (call that spam), then sets x to ham and y to spam. I.e., it's like
ham = y
spam = x + y
x = ham
y = spam
By contrast,
x = y
y = x + y
sets x to y, then sets y to x (which == y) plus y, so it's equivalent to
x = y
y = y + y
It is explained in the docs in the section entitled "Evaluation order":
... while evaluating an assignment, the right-hand side is evaluated
before the left-hand side.
The first expression:
Creates a temporary tuple with value y,x+y
Assigned in to another temporary tuple
Extract the tuple to variables x and y
The second statement is actually two expressions, without the tuple usage.
The surprise is, the first expression is actually:
temp=x
x=y
y=temp+y
You can learn more about the usage of comma in "Parenthesized forms".
An observation regarding the left-hand side as well: the order of assignments is guaranteed to be the order of their appearance, in other words:
a, b = c, d
is equivalent functionally to precisely (besides t creation):
t = (c, d)
a = t[0] # done before 'b' assignment
b = t[1] # done after 'a' assignment
This matters in cases like object attribute assignment, e.g.:
class dummy:
def __init__(self): self.x = 0
a = dummy(); a_save = a
a.x, a = 5, dummy()
print(a_save.x, a.x) # prints "5 0" because above is equivalent to "a = dummy(); a_save = a; t = (5, dummy()); a.x = t[0]; a = t[1]"
a = dummy(); a_save = a
a, a.x = dummy(), 5
print(a_save.x, a.x) # prints "0 5" because above is equivalent to "a = dummy(); a_save = a; t = (dummy(), 5); a = t[0]; a.x = t[1]"
This also implies that you can do things like object creation and access using one-liners, e.g.:
class dummy:
def __init__(self): self.x = 0
# Create a = dummy() and assign 5 to a.x
a, a.x = dummy(), 5
I've recently started using Python and this "feature" baffled me. Although there are many answers given, I'll post my understanding anyway.
If I want to swap the values of two variables, in JavaScipt, I'd do the following:
var a = 0;
var b = 1;
var temp = a;
a = b;
b = temp;
I'd need a third variable to temporarily hold one of the values. A very straightforward swap wouldn't work, because both of the variables would end up with the same value.
var a = 0;
var b = 1;
a = b; // b = 1 => a = 1
b = a; // a = 1 => b = 1
Imagine having two different (red and blue) buckets and having two different liquids (water and oil) in them, respectively. Now, try to swap the buckets/liquids (water in blue, and oil in red bucket). You can't do it unless you have an extra bucket.
Python deals with this with a "cleaner" way/solution: Tuple Assignment.
a = 0
b = 1
print(a, b) # 0 1
# temp = a
# a = b
# b = temp
a, b = b, a # values are swapped
print(a, b) # 1 0
I guess, this way Python is creating the "temp" variables automatically and we don't have to worry about them.
In the second case, you assign x+y to x
In the first case, the second result (x+y) is assigned to y
This is why you obtain different results.
After your edit
This happen because, in the statement
x,y = y,x+y
all variables at the right member are evaluated and, then, are stored in the left members. So first proceed with right member, and second with the left member.
In the second statement
x = y
y = x + y
yo first evaluated y and assign it to x; in that way, the sum of x+y is equivalent to a sum of y+y and not of x+x wich is the first case.
The first one is a tuple-like assignment:
x,y = y,x+y
Where x is the first element of the tuple, and y is the second element, thus what you are doing is:
x = y
y = x+y
Wheras the second is doing a straight assign:
x=y
x=x+y
Other answers have already explained how it works, but I want to add a really concrete example.
x = 1
y = 2
x, y = y, x+y
In the last line, first the names are dereferenced like this:
x, y = 2, 1+2
Then the expression is evaluated:
x, y = 2, 3
Then the tuples are expanded and then the assignment happens, equivalent to:
x = 2; y = 3
For newbies, I came across this example that can help explain this:
# Fibonacci series:
# the sum of two elements defines the next
a, b = 0, 1
while a < 10:
print(a)
a, b = b, a+b
With the multiple assignment, set initial values as a=0, b=1.
In the while loop, both elements are assigned new values (hence called 'multiple' assignment). View it as (a,b) = (b,a+b). So a = b, b = a+b at each iteration of the loop. This continues while a<10.
RESULTS:
0
1
1
2
3
5
8
Let's grok the difference.
x, y = y, x + y
It's x tuple xssignment, mexns (x, y) = (y, x + y), just like (x, y) = (y, x)
Stxrt from x quick example:
x, y = 0, 1
#equivxlent to
(x, y) = (0, 1)
#implement xs
x = 0
y = 1
When comes to (x, y) = (y, x + y)
ExFP, have x try directly
x, y = 0, 1
x = y #x=y=1
y = x + y #y=1+1
#output
In [87]: x
Out[87]: 1
In [88]: y
Out[88]: 2
However,
In [93]: x, y = y, x+y
In [94]: x
Out[94]: 3
In [95]: y
Out[95]: 5
The result is different from the first try.
Thx's because Python firstly evaluates the right-hand x+y
So it equivxlent to:
old_x = x
old_y = y
c = old_x + old_y
x = old_y
y = c
In summary, x, y = y, x+y means,
x exchanges to get old_value of y,
y exchanges to get the sum of old value x and old value y,
a, b = 0, 1
while b < 10:
print(b)
a, b = b, a+b
Output
1
1
2
3
5
8
the variables a and b simultaneously get the new values 0 and 1, the same a, b = b, a+b, a and b are assigned simultaneously.

Categories

Resources