why does this .pop(0) work like this - python

def f(x, y):
x.append(x.pop(0))
x.append(y[0])
return x
a = [4,5]
b = [1,2,3]
w = f(a,b) + f(a,b)
w turns out to be [4,1,5,1,4,1,5,1] However if I manually go through the code (in my head), I get [5,4,1,4,1,5,1]
Why is this?
f(a,b) = [5,4,1] right?, so then a would be = [5,4,1] and b = [1,2,3].
So then f(a,b) = [4,1,5,1] which would be:
[5,4,1] + [4,1,5,1] = [5,4,1,4,1,5,1] NOT [4,1,5,1,4,1,5,1]
Why does the code change this? What am I doing wrong when trying to run through the code myself?

Both calls return the same list, namely the object bound to a, resulting in the second returned value (which is still the object bound to a) being added to itself. The function only mutates the list, never replaces it.

Your problem is that your code both changes the original list and although returns a reference to it. When you invoke f for the second time (never use one-letter names !!!) you change the result of the original call as well. Let's do it by stages:
n [53]: a1 = f(a,b)
In [54]: a
Out[54]: [5, 4, 1]
In [55]: a2 = f(a,b)
In [56]: a2
Out[56]: [4, 1, 5, 1]
In [57]: a
Out[57]: [4, 1, 5, 1]
This illustrates my point (function id returns reference to an object)
In [77]: id(a)
Out[77]: 145114860
In [78]: id (f(a,b))
Out[78]: 145114860
As you may see, your function has a side effect. If you rewrite it like this
def f(x, y):
x.append(x.pop(0))
x.append(y[0])
return copy(x)
The second call will not on impact the result of the first call -
In [74]: id(a)
Out[74]: 145114860
In [75]: id (f(a,b))
Out[75]: 145113356
and the result will be [5, 4, 1, 4, 1, 5, 1]

f(a,b) = [5,4,1] right?, so then a would be = [5,4,1] and b = [1,2,3].
All correct. However. If you look at what f is doing, it is just returning the mutated x (i.e. mutating a). So do it twice:
f(a,b)
Out[40]: [5, 4, 1]
a
Out[41]: [5, 4, 1]
f(a,b)
Out[42]: [4, 1, 5, 1]
a
Out[43]: [4, 1, 5, 1]
then concatenate that with itself. That's what w is: just a + a, after having mutated a twice.

Related

Numpy: Function to take arrays a and b and return array c with elements 0:b[0] with value a[0], values b[0]:b[1] with value a[1], and so on

Say I have two arrays:
a = np.asarray([0,1,2])
b = np.asarray([3,7,10])
Is there a fast way to create:
c = np.asarray([0,0,0,1,1,1,1,2,2,2])
# index 3 7 10
This can be done using a for loop but I wonder if there is a fast internal numpy function that achieves the same thing.
You can use diff to get the successive differences, r_ to add the first b value and repeat to duplicate the values:
a = np.asarray([0, 1, 2])
b = np.asarray([3, 7, 10])
c = np.repeat(a, np.r_[b[0], np.diff(b)])
Output: array([0, 0, 0, 1, 1, 1, 1, 2, 2, 2])

Loop append of numpy array element in python

Who can explain how to loop add an element to the numpy array by condition?
I wrote some code that should do add element 2 if i element of array A is 0 and add element 1 if i element of array A is not 0.
Here is the code itself:
import numpy as np
def finalconcat(somearray):
for i in somearray:
arraysome=[]
if somearray[i]==0:
arraysome=np.append(arraysome,[2],axis=0)
else:
arraysome=np.append(arraysome,[1],axis=0)
return arraysome
Let me give you an example:
A=np.array([1,0,2,3,4,5])
C=finalconcat(B)
print(C)
It should come out:
[1,2,1,1,1,1]
But it comes out like:
[1.]
Please explain to me what is wrong here, I just don't understand what could be wrong...
You have several issues:
arraysome=[] is inside your loop so for each iteration of somearray you are emptying arraysome. Consequently, you can never end up with more than one element in arraysome when you are all done.
You have for i in somearray. On each iteration i will be the next element of somearray; it will not be iterating indices of the array. Yet later you have if somearray[i]==0:. This should just be if i==0:.
If you want the resulting elements of arraysome to be integers rather than floats, then you should initialize it to be a an numpy array of integers.
You have C=finalconcat(B), but B is not defined.
You should really spend some time reading the PEP 8 – Style Guide for Python Code.
import numpy as np
def finalconcat(somearray):
arraysome = np.array([], dtype=np.int)
for i in somearray:
if i == 0:
arraysome = np.append(arraysome, [2], axis=0)
else:
arraysome = np.append(arraysome, [1], axis=0)
return arraysome
a = np.array([1, 0, 2, 3, 4, 5])
c = finalconcat(a)
print(c)
Prints:
[1 2 1 1 1 1]
For iteration like this it's better to use lists. np.append is just a poorly named cover for np.concatenate, which returns a whole new array with each call. List append works in-place, and is more efficient. And easier to use:
def finalconcat(somearray):
rec = [2 if i==0 else 1 for i in somearray]
# arr = np.array(rec)
return rec
In [31]: a = np.array([1, 0, 2, 3, 4, 5])
In [32]: np.array([2 if i==0 else 1 for i in a])
Out[32]: array([1, 2, 1, 1, 1, 1])
But it's better to use whole-array methods, such as:
In [33]: b = np.ones_like(a)
In [34]: b
Out[34]: array([1, 1, 1, 1, 1, 1])
In [35]: b[a==0] = 2
In [36]: b
Out[36]: array([1, 2, 1, 1, 1, 1])
or
In [37]: np.where(a==0, 2, 1)
Out[37]: array([1, 2, 1, 1, 1, 1])

Numpy array insert every second element from second array

I have two arrays of the same shape and now want to combine them by making every odd element and 0 one of the first array and every even one of the second array in the same order.
E.g.:
a = ([0,1,3,5])
b = ([2,4,6])
c = ([0,1,2,3,4,5,6])
I tried something including modulo to identify uneven indices:
a = ([0,1,3,5])
b = ([2,4,6])
c = a
i = 0
j = 2
l = 0
for i in range(1,22):
k = (i+j) % 2
if k > 0:
c = np.insert(c, i, b[l])
l+=1
else:
continue
I guess there is some easier/faster slicing option, but can't figure it out.
np.insert would work well:
>>> A = np.array([1, 3, 5, 7])
>>> B = np.array([2, 4, 6, 8])
>>> np.insert(B, np.arange(len(A)), A)
array([1, 2, 3, 4, 5, 6, 7, 8])
However, if you don't rely on sorted values, try this:
>>> A = np.array([5, 3, 1])
>>> B = np.array([1, 2, 3])
>>> C = [ ]
>>> for element in zip(A, B):
C.extend(element)
>>> C
[5, 1, 3, 2, 1, 3]
read the documentation of the range
for i in range(0,10,2):
print(i)
will print [0,2,4,6,8]
From what I understand, the first element in a is always first the rest are just intereleaved. If that is the case, then some clever use of stacking and reshaping is probably enough.
a = np.array([0,1,3,5])
b = np.array([2,4,6])
c = np.hstack([a[:1], np.vstack([a[1:], b]).T.reshape((-1, ))])
You could try something like this
import numpy as np
A = [0,1,3,5]
B = [2,4,6]
lst = np.zeros(len(A)+len(B))
lst[0]=A[0]
lst[1::2] = A[1:]
lst[2::2] = B
Even though I don't understand why you would make it so complicated

How to fix the multiple value assignment to the variables in the python code below?

Given a list of unique numbers in python, I need to swap the positions of the maximum and minimum numbers in the list.
Apart from the traditional way of doing by getting the positions of the numbers by for loop, I tried to do that by the in-built python functions and used it directly in the multiple variables assignment method which is shown below.
a = [i for i in range(6, 1, -1)]
print("The original array is =", a) # print's [6, 5, 4, 3, 2]
index_max = a.index(max(a))
index_min = a.index(min(a))
# a[ a.index(max(a)) ], a[ a.index(min(a)) ] = min(a), max(a) #print's [6, 5, 4, 3, 2]
a[index_max], a[index_min] = min(a), max(a) # print's [2, 5, 4, 3, 6]
print("The swapped array is =", a)
Line no.7 doesn't work as it gives the output [6, 5, 4, 3, 2], instead
of [2, 5, 4, 3, 6].
Whereas line no.8 works perfectly!!
According to docummentation of Python:
WARNING: Although the definition of assignment implies
that overlaps between the left-hand side and the right-
hand side are `safe' (e.g., "a, b = b, a" swaps two
variables), overlaps within the collection of assigned-to
variables are not safe! For instance, the following program
prints "[0, 2]":
x = [0, 1]
i = 0
i, x[i] = 1, 2
print x
So the problem is that, in line 7, Python first does
a [a.index(max(a))] = min(a)
Now, a = [2, 5, 4, 3, 2]. After that, Python does
a [a.index(min(a))] = max(a)
But min(a) = 2, and a.index(2) returns 0. So, in the end, a = [6, 5, 4, 3, 2]. That's why assign the index of min and max before swap the variables does work.
Reference:
https://docs.python.org/2.0/ref/assignment.html
Edit: reference to Python 3 as suggested by #chepner:
Although the definition of assignment implies that overlaps between
the left-hand side and the right-hand side are ‘simultaneous’ (for
example a, b = b, a swaps two variables), overlaps within the
collection of assigned-to variables occur left-to-right, sometimes
resulting in confusion. For instance, the following program prints [0,
2]:
x = [0, 1]
i = 0
i, x[i] = 1, 2 # i is updated, then x[i] is updated
print(x)
Reference:
https://docs.python.org/3/reference/simple_stmts.html#assignment-statements
The important here is the order of the operations. When you do:
a[ a.index(max(a)) ], a[ a.index(min(a)) ] = min(a), max(a)
Python do things in that order:
max(a) # >> 6
a.index(max(a)) # >> 0
a[...] = min(a) # >> a[0] = 2
Then, it do the same with the second member:
min(a) # >> 2
a.index(min(a)) # >> 0
a[...] = max(a) # >> a[0] = 6
The bad behaviour is natural, since you changed the index during the operation...

Efficient way to iterate python loop until previous position

I have a list a and I need to iterate from position 2 until its previous position 1.
# old index - 0 1 2 3 4
a = [1,2,3,4,5]
# new index - 2,3,4,0,1
# new value - 3,4,5,1,2
cnt = 0
while True:
for i in range(2,len(a)):
print(a[i])
for i in range(len(a)-2-1):
print(a[i])
break
I'm using 2 for loops but I believe there should be a better way to do it.
Let's assume we start with a list a = [1,2,3,4,5].
You can use collections.deque and its method deque.rotate:
from collections import deque
b = deque(a)
b.rotate(-2)
print(b)
deque([3, 4, 5, 1, 2])
Or, if you are happy to use a 3rd party library, you can use NumPy and np.roll:
import numpy as np
c = np.array(a)
c = np.roll(c, -2)
print(c)
array([3, 4, 5, 1, 2])
you can create a new list combining the elements after the particular value and before the particular value, let's say 3 in your case:
a = [1, 2, 3, 4, 5]
piv = a.index(3)
print(a[piv:] + a[:piv])
which gives you [3, 4, 5, 1, 2]
a = [1,2,3,4,5]
position = 2
for item in a[position:] + a[:position]:
print(item)
A base python based solution
a[2::] + a[:2:]
Gives
[3, 4, 5, 1, 2]
A generic version of the same would be
rotate_from = 2
a[rotate_from::] + a[:rotate_from:]
Write a function for rotate list,
In [114]: def rotate(lst, n):
...: return lst[-n:] + lst[:-n]
...:
In [115]: rotate(a,-2)
Out[115]: [3, 4, 5, 1, 2]

Categories