What does this construct do? [duplicate] - python

This question already has answers here:
Is there a standardized method to swap two variables in Python?
(8 answers)
Closed 6 years ago.
Example
num = [0,3,5,3,0,0,9,8]
Output should be
[3,5,3,9,8,0,0,0]
The solution to this in Python is
def moveZeroes(self, nums):
zero, cur = -1, 0
while cur < len(nums):
if nums[cur] != 0:
# update zero index when current is not zero
zero += 1
nums[cur], nums[zero] = nums[zero], nums[cur]
cur += 1
My question is I have seen similar statement like this a lot
nums[cur], nums[zero] = nums[zero], nums[cur]
What is this statement in particular doing?

The idiom
>>> a, b = b, a
swaps the values hold in a and b in one step so that a now points to the value that b used to point to, et vice versa:
>>> a, b = 1, 2
>>> a
1
>>> b
2
>>> a, b = b, a
>>> a
2
>>> b
1
Technically, the right-hand side creates a throwaway tuple, and the left-hand side is a tuple-unpacking assignment.
nums[cur], nums[zero] = nums[zero], nums[cur]
then means "swap the elements at index zero and at index cur.

This code nums[cur], nums[zero] = nums[zero], nums[cur] is swapping two values in the nums array. It is the same as if you had written:
temp = nums[cur]
nums[cur] = nums[zero]
nums[zero] = temp
When you use commas on both sides of the = assignment operator, Python essentially makes all of the assignments at once, so you don't need a temp variable.

It is swapping the values.
a, b = b, a
Now a has the value of b, and b has the value of a

This is Python's tuple packing and unpacking feature.
It's functionally identical to
temp = nums[cur]
nums[cur] = nums[zero]
nums[zero] = temp
but more efficient to the computer and more readable to programmers.
Further reading: https://stackoverflow.com/a/14836456/5399734

It's a variable swap, Python-style. It constructs a tuple of two values, the values at zero and cur, then unpacks that tuple and assigns the values to the indices at cur and zero; by reversing the indices assigned to, it swaps the values.
Note that the code could be simplified dramatically (though possibly at the expense of running slightly slower) by repurposing the key argument of the sort method to let Python do the work at the C layer:
def moveZeroes(self, nums):
nums.sort(key=lambda x: x == 0)
# Or more efficiently but obscurely:
# nums.sort(key=(0).__eq__)
# Or with an operator import to get speed with less obscurity:
# nums.sort(key=operator.not_)
Since Python's TimSort algorithm is stable, this preserves the order for all the non-zero values while moving the zeroes to the end.

It is first evaluating both of the values on the right, then it is substituting them to the matching slots on the left. So basically:
a, b = b, a
is like:
c = b
d = a
a = c
b = d
It is particularly useful to swap values or perform some operations on them without creating additional variables.

Related

List Problem in python to sort a list of string without using sort or sorted function

I am stuck in this list problem, I am unable to solve it.
list1= ["aaditya-2", "rahul-9", "shubhangi-4"]
I need to sort this list without using sort/sorted function.... and also it should sort on the basis of numbers at the last..
Output:
["aaditya-2", "shubhangi-4", "rahul-9"]
OR
["rahul-9", "shubhangi-4", "aaditya-2" ]
You could try something like this:
def sort_arr(arr, function):
arr2 = [function(i) for i in arr] # apply your function to all the elements in the array, in this case it is get the last digit
for i in range(1, len(arr2)): # begin looping from the first index of the array to the last index
k = arr2[i] # assign the value of the ith item to a variable
j = i - 1 # keep track of the index begin considered
while j >= 0 and k < arr2[j]: # while k is less than the item before it, do
arr2[j + 1] = arr2[j] # shift the ith value one step to the front of the array
j -= 1
arr2[j + 1] = k # once the correct position has been found, position arr2[i] at its correct location
return arr2 # return sorted array
print(sort_arr(list1, lambda x: int(x[-1]))) # the lambda gets the last digit and turns it into an integer
Learn more about lambda's here.
This is an implementation of insertion sort. Learn more about it here.
Hope this helps!
EDIT: Just realized this did not directly answer OP's question. Updated answer to match.
As I understand it, it's a question of ordering. I don't think this is about implementing a sorting algorithm. Here I define a order function that works on two strings and orders them by last character. This is applied 3 times to sort 3-element list.
def order(a, b):
return (b, a) if a[-1] > b[-1] else (a, b)
list1 = ["aaditya-2", "rahul-9", "shubhangi-4"]
a, b, c = list1
a, b = order(a, b)
a, c = order(a, c)
b, c = order(b, c)
list1 = [a, b, c] # ["aaditya-2", "shubhangi-4", "rahul-9"]
For reverse sort, just use < in the order function.

Difference between defining multiple variable at a time and individually

I am a newbie in Python and I'm trying to learn Python through self-learning. I was trying to build Fibonacci series using a while loop. Here is my code, which doesn't return the desired result. Could anyone explain the problem?
a = 0
b = 1
while b<100:
print(b)
a = b
b = a + b
If we define a, b simultaneously like a, b = b, a+b, this works perfectly. Why is this happening? I don't understand because in both cases I am defining a and b the same way.
This is because programming languages like Python, and many others, execute the statements you write in the order you write them.
This means that by the time you execute b = a + b, the value of a has already changed in the previous line.
An easy way to solve this would be using a third variable to store the results temporarily.
a = 0
b = 1
c = 1
while c < 100:
print(c)
c = a + b
a = b
b = c
You are making one small mistake.
When you do a = b, you are changing the value of a. After this, when you do b=a+b, it is actually equivalent to b = b+b => b=2b.
To avoid this, use a temporary variable temp and storethe value of a in it. Then change the value of a using a = b. Then do, a = a+b.
Following is the code:
a=0
b=1
while b<100:
print(b)
temp = a
a = b
b = temp+b
When you do a, b = b, a+b, the previous value of a is used for calculating the new b, we have don a similar thing above by storing the previous value of a in temp
Operator "comma" (,) in Python is used to create a tuple, and it is allowed to omit the parentheses that surround a tuple. The expression a, b = b, a+b is actually an assignment of one tuple to another:
(a, b) = (b, a + b)
This statement is executed by evaluating the tuple constructor on the right-hand side (b, a + b). At this point, a new anonymous tuple (let's call it c) is created and the original values of a and b are not needed anymore. The tuple is then assigned elementwise to the tuple on the left-hand side. The new value of a becomes c[0] (that is, former b) and the new value of b becomes c[1] (that is, former a+b).
Your code is not working because you are changing the value of a before evaluating b. In the Fibonacci series, you want the previous value of a and b. You can use list as above or can introduce another variable to store values.
while True:
temp = a + b
if temp >100:
break
print(temp)
a = b
b = temp
For reference, here is a simple implementation using list:
lst = [0, 1]
while True:
temp = lst[-1]+lst[-2]
if temp>100:
break
lst.append(temp)
print(lst)

Python: Use a Loop to Manipulate Arrays [duplicate]

This question already has answers here:
Extract first item of each sublist
(8 answers)
Closed 4 years ago.
I have to perform the same operation on a number of arrays. Is there a way to use a loop in Python to carry out this repetitive task?
For example, I have 5 arrays: A, B, C, D, and E.
I want to carry out the following:
A = A[0]
B = B[0]
C = C[0]
D = D[0]
E = E[0]
Is there any way to do this using a loop or some other technique to avoid typing almost the same thing multiple times?
My question has been marked as a duplicate of this question. There, the person is asking how to extract the first element from each list (or in my case array). I am not simply trying to extract the first element. I actually want to replace each array with it's first element -- literally A = A[0].
Some are saying this is not a good idea, but this is actually what I want to do. To give some context, I have code that leaves me with a number of 2D arrays, with shapes n x m. When n = 1, the first dimension is irrelevant, and I would like to dispense with that dimension, which is what A = A[0] does. My code needs to handle both cases where n = 1 and cases when n > 1.
In other words, when n = 1, my code results in an array A that is of the following form: A = array([[a]]), and I want to change it so that A = array([a]). And to reiterate, I need the flexibility of allowing n > 1, in which case A = array([[a1],[a2],...]). In that case, my code will not execute A = A[0].
The solution by Mark White below works, if you change the last line to:
A,B,C,D,E = [x[0] for x in [A,B,C,D,E]]
What's interesting is that this solution makes the code more compact, but actually involves as many characters as (an technically more than) the brute force approach.
I do think it is a pretty easy problem ,in my case ,I use three array ,but I think you can do five , my dear friend!
A = [1,3,4]
B = [2,4,5]
C = [54,5,6]
A,B,C = [x[0] for x in [A,B,C]]
Simply create a list of lists (or, specifically, references to A, B, C, etc.)
l = [A, B, C, D, E]
Then, you can iterate over l however you choose.
for i in range(len(l)):
l[i] = l[i][0]
Note that this will update l[i] rather than the lists (A, B, C, ...) themselves.

python fibonacci - what is the difference? [duplicate]

This question already has answers here:
Python variable assignment question
(6 answers)
Closed 6 years ago.
I am learning python and I have some question:
What is the difference between
a,b = 0,1
for x in range(100):
print(a)
a=b
b=a+b
and
a,b = 0,1
for x in range(100):
print(a)
a,b = b, a+b
First one gives bad result, but why?
Because you first set a = b, your new b will have the value of twice the old b. You overwrite a to early. A correct implementation should use a temporary variable t:
a,b = 0,1
for x in range(100):
print(a)
t=a
a=b
b=t+b
This is basically what you do by using sequence assignment.
In your original code you have:
a,b = 0,1
for x in range(100):
print(a)
a=b # a now is the old b
b=a+b # b is now twice the old a so b'=2*b instead of b'=a+b
So this would result in jumping by multiplying with two each time (after first loading in 1 into a the first step).
An equivalent problem is the swap of variables. If you want a to take the value of b and vice versa, you cannot write:
#wrong swap
a = b
b = a
Because you lose the value of a after the first assignment. You can use a temporary t:
t = a
a = b
b = t
or use sequence assignment in Python:
a,b = b,a
where a tuple t = (b,a) is first created, and then assigned to a,b.

C Pointer arithmetic in Python

I'm trying to convert a simple C program into Python but as I don't know anything about C and a little about Python its just difficult for me..
I'm stuck at C pointers.
There is a function that takes an unsigned long int pointer and adds its values to some variables within a while-loop:
uint32_t somename(const uint32_t *z) {
while(....) {
a += z[0]
b += z[1]
c += z[2]
z += 3
}
}
Can someone please tell me how to accomplish the same thing in python?
(The part that I didn't understand at all is " z += 3 ")
I'm aware that there aren't pointers in python. (at least not like C) But the problem is that I don't know what C pointers exactly do and therefor can't make this happen in python.
A similar code snippet in Python might be:
def somename(z):
i = 0
while (....):
a += z[i]
b += z[i+1]
c += z[i+2]
i += 3
In C, z works sort of like an array index, except it starts at whatever the address of the start of the array is, rather than starting at 0. There is no analogous concept in Python, so you need to use a list index explicitly.
Whatever is inside (....) will need modification too. I'll leave that as an exercise for you, since it's unspecified in the question.
What z += 3 means is basically advance the pointer 3 elements down. Say you have a pointer to an array in C called lst which contains [1, 2, 3, 4]. The pointer lst points to the first element such that *lst is equivalent to lst[0]. Furthermore, *(lst+1) is equivalent to lst[1].
Assuming z is passed as a list (in the corresponding python code). The z += 3 can be translated to del z[:3] which moves the element 3 to 0.
However in python, you need to copy the array before doing that, because with the del-statement, the array gets modified.
In C you are able to access the elements before the pointed index through negative indices. This can be done with an "invisible" offset nested in a class. This offset is always added onto the index when the list is accessed.
The following class demonstrates the behavior.
class pointer_like:
def __init__(self, lst):
self.lst = lst; self.offset = 0
# self[index]
def __getitem__(self, index):
return self.lst[self.offset + index]
# self += offset
def __iadd__(self, offset):
self.offset += offset
# other member functions...
# as your example above
def somename(z):
z = pointer_like(z)
while (....):
a += z[0]
b += z[1]
c += z[2]
z += 3
>>> # other example
>>> z = pointer_like([0, 1, 2, 3, 4, 5])
>>> z[0]
0
>>> z += 3
>>> z[0]
3
>>>
>>> # with normal python lists, this would mean third last element
>>> z[-3]
0
>>> z += -5
>>> z[2]
0
>>>
>>> # this is special, because z.offset is negative (-2),
>>> # when a list item is accessed through a negative index,
>>> # it is counted from the end of the array in python.
>>> # In this case, it is -2, so the second last is accessed
>>> # In C this would cause undefined behavor, on most
>>> # platforms this causes an access violation
>>> z[0]
4
Note that pyhon also has a += operator for lists, but this allows to append another list at the end.

Categories