How can I have references of lists in Python - python

Say I have two following lists.
x = [1, 2, 3]
y = [4, 5, 6]
Now I want a list that contains references to these lists,
So instead of wanting
z = [x, y] -> [[1, 2, 3], [4, 5, 6]]
I want the following
z = [ref of x, ref of y]
How can I achieve that in Python?

z = [x, y] is the way to use references:
>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
>>> z = [x, y]
>>> x[0] = 0
>>> z
[[0, 2, 3], [4, 5, 6]]
If you want to copy, use the slice notation or the copy module:
>>> z=[x[:],y[:]]
>>> x[0] = 11
>>> x
[11, 2, 3]
>>> z
[[0, 2, 3], [4, 5, 6]]

z=[x,y] keeps the references, not the copies. This can be proved as:
>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
>>> id(x),id(y)
(139643028466504, 139643028484320)
>>> z=[x,y]
>>> id(z[0]),id(z[1])
(139643028466504, 139643028484320)
As you can see addresses of x and y are similar to addresses z[0] and z[1], which clearly is the definition of reference.

Related

Need help in relation to the sort function in Python [duplicate]

This question already has answers here:
Sorting list based on values from another list
(20 answers)
Closed 1 year ago.
Hello I have a question related to the sort function in python.
So if I have 2 arrays x and y e.g
X = [1, 5, 6, 2]
Y = [2, 7, 5, 1]
If i sort x, y wont be effected but what if i want it to like follow that index if that makes sense like e.g
>>> X
[1, 2, 5, 6]
>>> Y
[2, 1, 7, 5]
You can sort the indices in range(len(X)) based on the values of X, then update X and Y accordingly:
>>> X = [1, 5, 6, 2]
>>> Y = [2, 7, 5, 1]
>>> Z = sorted(range(len(X)), key=lambda i: X[i])
>>> X, Y = map(list, zip(*((X[i], Y[i]) for i in Z)))
>>> X
[1, 2, 5, 6]
>>> Y
[2, 1, 7, 5]

Numpy vectorization: Find intersection between list and list of lists

I am trying to find the intersection between a list and a list of lists. This is trivially solved with a simple for loop:
def find_intersec(x,y):
result = []
for i in range(len(y)):
if set(x).intersection(set(y[i])):
result.append(y[i])
return(result)
x = [1,2,3,4,5,6]
y = [[1,2,3], [4,5,6], [9,10,11]]
find_intersec(x,y)
How can I change the above into a numpy vectorization solution? I have tried numpy.intersect1d() with no success.
You can have a function like this:
import numpy as np
def find_intersec_vec(x, y):
y_all = np.concatenate(y)
y_all_in = np.isin(y_all, x)
splits = np.cumsum([0] + [len(lst) for lst in y])
y_in = np.logical_or.reduceat(y_all_in, splits[:-1])
return [lst for lst, isin in zip(y, y_in) if isin]
Test:
x = [1, 2, 3, 4, 5, 6]
y = [[1, 2, 3], [4, 5], [6, 7], [8, 9, 10, 11]]
print(find_intersec(x, y))
# [[1, 2, 3], [4, 5], [6, 7]]
print(find_intersec_vec(x, y))
# [[1, 2, 3], [4, 5], [6, 7]]
As you mentioned, numpy.intersect1d() can be used:
import numpy as np
x = [1,2,3,4,5,6]
y = [[1,2,3], [4,5,6], [9,10,11]]
intersec = [np.intersect1d(i, x) for i in y if len(np.intersect1d(i, x)) > 0]
result:
[array([1, 2, 3]), array([4, 5, 6])]

Is there a way to combine a list like this?

assume that a and b are list.
a = [[1], [2]]
b = [[5, 6, 7], [3, 4, 5]]
I want to get a list which is
[[1,5,6,7], [2,3,4,5]]
Is there any way to do that effectively? Either lists or numpy array is OK.
zip is your friend:
>>> a = [[1], [2]]
>>> b = [[5, 6, 7], [3, 4, 5]]
>>> [x+y for x, y in zip(a, b)]
[[1, 5, 6, 7], [2, 3, 4, 5]]
You can also use map; the operator module provides a ready-made definition of lambda x,y: x + y for such uses.
>>> import operator
>>> list(map(operator.add, a, b))

Python: Get set of values, by multiplication

I want to get a list of values, by multiplication, like this:
[[1, 2, 3], [2, 4, 6], [3, 6, 9]]
So, I tried:
rGen = (i for i in range(1, 4))
matriz = [[x * y for y in rGen] for x in rGen]
And I get:
[[2, 3]]
How can I solve this?
Like this?
>>> r=range(1,4)
>>> [[x * y for x in r] for y in r]
[[1, 2, 3], [2, 4, 6], [3, 6, 9]]
The difference is how you use/assign the generator. As illustrated by this example (Python 2.x):
>>> r1=(i for i in range(1,4))
>>> r2=range(1,4)
>>> r3=[i for i in range(1,4)]
>>> r1
<generator object <genexpr> at 0x6ffffe1e4b0>
>>> r2
[1, 2, 3]
>>> r3
[1, 2, 3]
>>> [[x * y for x in r1] for y in r1]
[[2, 3]]
>>> [[x * y for x in r2] for y in r2]
[[1, 2, 3], [2, 4, 6], [3, 6, 9]]
>>> [[x * y for x in r3] for y in r3]
[[1, 2, 3], [2, 4, 6], [3, 6, 9]]
In the first example (r1), you get a generator object, which will only generate your sequence once, while in the other two examples you get lists, which you can use in a nested list comprehension (they will always evaluate to the same, no matter how many times you access them).
In Python 3.x, range() returns a different type, but the behavior is similar:
>>> r1=(i for i in range(1,4))
>>> r2=range(1,4)
>>> r3=[i for i in range(1,4)]
>>> r1
<generator object <genexpr> at 0x6ffffe7a518>
>>> r2
range(1, 4)
>>> r3
[1, 2, 3]
>>> [[x * y for x in r1] for y in r1]
[[2, 3]]
>>> [[x * y for x in r2] for y in r2]
[[1, 2, 3], [2, 4, 6], [3, 6, 9]]
>>> [[x * y for x in r3] for y in r3]
[[1, 2, 3], [2, 4, 6], [3, 6, 9]]
You are using the same generator (rGen) for both your outer and inner loop. What you should do is:
matrix = [[x * y for y in range(1,4)] for x in range(1,4)]
To return the product of elements of each list, you could do something like this,
>>> import operator
>>> from functools import reduce
>>> a = [[1, 2, 3], [2, 4, 6], [3, 6, 9]]
>>> [reduce(operator.mul, i, 1) for i in a]
[6, 48, 162]
>>>

Python lists Ids

Why is the id is of x changes in the following code while it still has the same value. I expect the id for x and z should be same in this case as the value remains the same at the end.
>>> x = [1, 2, 3]
>>> z = x
>>> id(z) == id(x)
True
>>> x = [1, 2, 3]
>>> id(z) == id(x)
False
>>> x
[1, 2, 3]
>>> z
[1, 2, 3]
>>>
What an object holds has nothing to do with its identity. id(x) == id(y) if and only if x and y both refer to the same object.
Maybe this example helps:
x = [1, 2, 3]
y = [1, 2, 3]
z = y
print x, y, z
y[0] = 1000
print x, y, z
which prints this:
[1, 2, 3] [1, 2, 3] [1, 2, 3]
[1, 2, 3] [1000, 2, 3] [1000, 2, 3]
y and z both refer to the same object, so modifying one variable modifies the value retrieved by the other, too. x remains the same because it's a separate object.
What you shouldn't forget is that initializing a variable with a literal list (like [1, 2, 3]) creates a new list object.
Whether or not the two lists contain the same elements does not imply that they should have the same id.
Two variables only have the same id if they refer to the same object, which the second z and x do not:
>>> x = [1, 2, 3]
>>> z = [1, 2, 3]
>>> x[0] = 999
>>> x
[999, 2, 3]
>>> z
[1, 2, 3]
This demonstrates that x and z are two distinct, unrelated lists.

Categories