Python lists Ids - python

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.

Related

Functions and Mutable lists in Python

sorry I'm new to python and still trying to wrap my head around few fundamentals. I know lists are mutable objects in python, but can't understand how the two functions below handle lists, and why one changes the list itself and the other doesn't
def f(x, y):
x.append(x.pop(0))
x.append(y[0])
return x
>>> a=[1,2,3]
>>> b=[1,2]
>>> f(a,b)
>>> [2, 3, 1, 1]
>>> a
>>> [2, 3, 1, 1]
def f(x, y):
y = y + [x]
return y
>>> a=[1,2,3]
>>> f(4,a)
>>> [1, 2, 3, 4]
>>> a
>>> [1, 2, 3]
Thank you
The + operation stores the result in a new list, while append operation appends the new value into the existing list
For example,
def f(x, y):
y = y + [x]
print(y)
y.append(x)
print(y)
a=[1,2,3]
f(4,a)
print(a)
gives
[1, 2, 3, 4]
[1, 2, 3, 4, 4]
[1, 2, 3]
y = y + [x] creates a new list y & hence the change is not reflected to the original list a & also the later append changes the new list y
but
def f(x, y):
y.append(x)
print(y)
y = y + [x]
print(y)
a=[1,2,3]
f(4,a)
print(a)
output
[1, 2, 3, 4]
[1, 2, 3, 4, 4]
[1, 2, 3, 4]
Here the append operation changes the original list a after that new list y is created
Simply put, the difference is in the function of append and +. append adds a new item to the list without creating a new list. + merges two lists together and creates a new list.
For more information, see DNS's answer here.

getting the difference between lists, keeping non-unique values

I am looking to get the difference between two lists.
I am looking for a solution like this only I want to consider non-unique list values.
x = [1, 1, 2, 2, 3]
y = [1, 2]
# i want
z = x - y
# z = [1, 2, 3]
The solution above my code turns the two lists into sets which allows the - operator to work on them but removes non unique values from the lists. Can you think of a simple 'one liner' solution that does what im looking for?
You could use collections.Counter to find the counts of elements in each list. Then you can take the difference and reconstruct a list from the results.
>>> from collections import Counter
>>> x = [1, 1, 2, 2, 3]
>>> y = [1, 2]
>>> [k for _ in range(v) for k,v in (Counter(x) - Counter(y)).iteritems()]
[1, 2, 3]
The drawback being, the order of the result has no real correlation with the order of the input lists. The fact that the result shown above looks sorted is implementation-dependent and possibly only a coincidence.
might not be fancy, first thing that came to mind..
x=[1,1,2,2,3]
y=[1,2]
_ = [ x.remove(n) for n in y if n in x ]
x
[1,2,3]
Here's my take:
x = [1, 1, 2, 2, 3]
y = [1, 2]
z = [n for n in y if (n in x) and x.remove(n)] + x
print(z) # -> [1, 2, 3]
x = [1, 1, 1, 2]
y = [1]
z = [n for n in y if (n in x) and x.remove(n)] + x
print(z) # -> [1, 1, 2]
You just described the union of two sets, so use set:
>>> list(set(x).union(set(y)))
[1, 2, 3]

How can I have references of lists in 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.

python List typecasting and setting values

I was trying this out
>>> x = [[1, 2, 3], 10.5]
>>> z = list(x)
>>> z[1] = 10.6
>>> z
[[1, 2, 3], 10.6]
>>> x
[[1, 2, 3], 10.5]
>>> z[0][2] = 5
>>> z
[[1, 2, 5], 10.6]
>>> x
[[1, 2, 5], 10.5]
Why the change is being reflected in x[0][2] ? and similarly not in x[1]???
The list(x) created a new top-level list thus changing its top-level values - like 10.5 - won't propagate to x. On the other hand, the inner list is a reference thus changes to it are shared amongst all containers containing it because they all contain the very same object. If you would like a separate copy of x, use copy.deepcopy.

List slicing in python every other value

Suppose I have a list x = [1,2,3] and I want to output every other value than the indexed one, is there a list operation I can use?, ie: x[0]=> [2,3], x[1] => [1,3], x[2] =>[1,2] ?
You could use this:
def exclude(l, e):
return [v for i, v in enumerate(l) if i != e]
>>> exclude(range(10), 3)
[0, 1, 2, 4, 5, 6, 7, 8, 9]
You could do it with a slice, but I'd be tempted to try:
a = [1, 2, 3]
b = a[:]
del b[1]
edit
The above does "technically" use a slice operation, which happens to be on list objects in effect a shallow-copy.
What's more flexible and shouldn't have any downsides is to use:
a = [1, 2, 3]
b = list(a)
del b[1]
The list builtin works on any iterable (while the slice operation [:] works on lists or those that are indexable) so that you could even extend it to constructs such as:
>>> a = '123'
>>> b = list(a)
>>> del b[0]
>>> ''.join(b)
'23'
You could use x[:i] + x[i+1:]:
In [8]: x = [1, 2, 3]
In [9]: i = 0
In [10]: x[:i] + x[i+1:]
Out[10]: [2, 3]
Depending on the context, x.pop(i) might also be useful. It modifies the list in place by removing and returning the i-th element. If you don't need the element, del x[i] is also an option.
>>> x = [1, 2, 3]
>>> x[:1] + x[2:]
[1, 3]
my_list = [1, 2, 3]
my_list.remove(my_list[_index_]) #_index_ is the index you want to remove
Such that: my_list.remove(my_list[0]) would yield [2, 3],
my_list.remove(my_list[1]) would yield [0, 3], and
my_list.remove(my_list[2]) would yield [1, 2].
So you want every value except the indexed value:
Where i is the index:
>>> list = [1,2,3,4,5,6,7,8]
>>> [x for x in list if not x == list[i]]
This will give you a list with no instances of the i't element, so e.g.:
>>> i = 2
>>> list = [1,2,3,4,5,6,7,1,2,3,4,5,6,7]
>>> [x for x in list if not x == list[i]]
[1, 2, 4, 5, 6, 7, 1, 2, 4, 5, 6, 7]
note how 3 is not in that list at all.
Every other is
x[::2], start at 0
x[1::2], start at 1

Categories