How to use index as a key in Python? - python

I have a list: v = [1,2,2,3]. I would like to use this list as a key. I can do it "manually":
x = {}
x[1,2,2,3] = 7
But
x[v] = 7
does not work. What is the easiest way to do what I need to do?
ADDED
I imagine the solution as something like that:
x[open(v)] = 7

The problem is that keys must be immutable, which lists are not. Tuples, however, are.
Simply convert v to a tuple:
x[tuple(v)] = 7
To elaborate, the above is the same as writing
x[1,2,2,3] = 7
and the latter is a syntactic variation of
x[(1,2,2,3)] = 7

Python has two similar data structures for storing lists of values. list is the mutable version: its values can be changed.
x = [1, 2, 2, 3]
x = list((1, 2, 3, 4))
tuple is the immutable version. Once created, its value can't be modified.
x = 1, 2, 2, 3
x = (1, 2, 2, 3)
x = tuple((1, 2, 2, 3))
Python doesn't let you use mutable types as dictionary keys, so you just need to create your tuple to a list:
x[tuple(v)] = 7

Dict keys must be hashable. Lists are not hashable, but tuples are. (A hash value of an object should never change during the life of the object. Moreover, two hashable objects which compare equal must have the same hash. Since lists are mutable, the only way to satisfy both conditions would be to make all lists return the same hash value. Rather than allowing this and subverting the purpose of hashes, Python make all mutable containers unhashable.)
x[tuple(v)]
x[1,2,2,3] works because a tuple is indicated by the use of commas, not the parentheses:
In [78]: 1,2,2,3
Out[78]: (1, 2, 2, 3)

Related

Lists are mutable but tuples are immutable, then how is the value of x changed when running function tuple?

I wrote 2 functions to try and understand the difference between immutable and mutable, one of the functions has a variable assigned to a list the other one is assigned to a tuple. After running the first function ( in the case of the list) it prints the updated value of x, but that wasn't supposed to happen for tuples because tuples are immutable right? How come they both print the updated x.
list
x = [1, 2, 3, 1, 2, 3]
def changeThem(x,y,z):
return [z if i == y else i for i in x]
print(changeThem(x, 2, 'zzz'))
tuple
x = ("apple", "banana", "cherry")
def changeThem(x,y,z):
return [z if i == y else i for i in x]
print(changeThem(x, "apple", 'zzz'))
Let's see this example.
x_list = [1, 2, 3, 1, 2, 3]
x_tuple = (1, 2, 3, 1, 2, 3)
def change_them_comprehension(x, y, z):
return [z if i == y else i for i in x]
def change_them_manual(x, y, z):
for idx, i in enumerate(x):
if i == y:
x[idx] = z
return x
print("list")
print(id(x_list)) # 1877716860160
print(id(change_them_comprehension(x_list, 2, 'zzz'))) # 1877716698368
print(id(change_them_manual(x_list, 2, 'zzz'))) # 1877716860160
print("tuple")
print(id(x_tuple)) # 1877716262336
print(id(change_them_comprehension(x_tuple, 2, 'zzz'))) # 1877716698368
print(id(change_them_manual(x_tuple, 2, 'zzz'))) # TypeError: 'tuple' object does not support item assignment
Notice how your change_them returns a new list comprehension, which is an absolutely different list from the original one (see they have different ids). This does not involve mutation; instead of editing the list you return a new list (in both the original tuple and original list cases).
Now check change_them_manual. This method does edit the input list/tuple and not creates a new one. See how the returned list is the same (same id). We can edit it because lists are mutable. However, when we try to do the same with the tuple we get an error, which tells us we can't edit the tuple, this is what not being mutable means.
Tuples are immutable in this way:
x = ("apple", "banana", "cherry")
x[0]='ananas'
TypeError: 'tuple' object does not support item assignment
In your second example, you're not changing the tuple.
Instead, you are defining new variable which is a list.
It's better you understand what you are trying to do here. The function you created is creating a new list. If you print out your x, you will see that it has not been changed.
Here are a couple of docs/articles that might help you get a better understanding of mutable vs. immutable...
python docs and real python explanation
Good luck exploring python!

elements of sets in python must be mutable or immutable?

I was reading sets in python http://www.python-course.eu/sets_frozensets.php and got confusion that whether the elements of sets in python must be mutable or immutable? Because in the definition section they said "A set contains an unordered collection of unique and immutable objects." If it is true than how can a set contain the list as list is mutable?
Can someone clarify my doubt?
>>> x = [x for x in range(0,10,2)]
>>> x
[0, 2, 4, 6, 8] #This is a list x
>>> my_set = set(x) #Here we are passing list x to create a set
>>> my_set
set([0, 8, 2, 4, 6]) #and here my_set is a set which contain the list.
>>>
When you pass the set() constructor built-in any iterable, it builds a set out of the elements provided in the iterable. So when you pass set() a list, it creates a set containing the objects within the list - not a set containing the list itself, which is not permissible as you expect because lists are mutable.
So what matters is that the objects inside your list are immutable, which is true in the case of your linked tutorial as you have a list of (immutable) strings.
>>> set(["Perl", "Python", "Java"])
set[('Java', 'Python', 'Perl')]
Note that this printing formatting doesn't mean your set contains a list, it is just how sets are represented when printed. For instance, we can create a set from a tuple and it will be printed the same way.
>>> set((1,2,3))
set([1, 2, 3])
In Python 2, sets are printed as set([comma-separated-elements]).
You seem to be confusing initialising a set with a list:
a = set([1, 2])
with adding a list to an existing set:
a = set()
a.add([1, 2])
the latter will throw an error, where the former initialises the set with the values from the list you provide as an argument. What is most likely the cause for the confusion is that when you print a from the first example it looks like:
set([1, 2])
again, but here [1, 2] is not a list, just the way a is represented:
a = set()
a.add(1)
a.add(2)
print(a)
gives:
set([1, 2])
without you ever specifying a list.

Obtaining length of list as a value in dictionary in Python 2.7

I have two lists and dictionary as follows:
>>> var1=[1,2,3,4]
>>> var2=[5,6,7]
>>> dict={1:var1,2:var2}
I want to find the size of the mutable element from my dictionary i.e. the length of the value for a key.
After looking up the help('dict'), I could only find the function to return number of keys i.e. dict.__len__().
I tried the Java method(hoping that it could work) i.e. len(dict.items()[0]) but it evaluated to 2.
I intend to find this:
Length of value for first key: 4
Length of value for second key: 3
when the lists are a part of the dictionary and not as individual lists in case their length is len(list).
Any suggestions will be of great help.
dict.items() is a list containing all key/value-tuples of the dictionary, e.g.:
[(1, [1,2,3,4]), (2, [5,6,7])]
So if you write len(dict.items()[0]), then you ask for the length of the first tuple of that items-list. Since the tuples of dictionaries are always 2-tuples (pairs), you get the length 2. If you want the length of a value for a given key, then write:
len(dict[key])
Aso: Try not to use the names of standard types (like str, dict, set etc.) as variable names. Python does not complain, but it hides the type names and may result in unexpected behaviour.
You can do this using a dict comprehension, for example:
>>> var1 = [1,2,3,4]
>>> var2 = [5,6,7]
>>> d = {1:var1, 2:var2}
>>> lengths = {key:len(value) for key,value in d.iteritems()}
>>> lengths
{1: 4, 2: 3}
Your "Java" method would also nearly have worked, by the way (but is rather unpythonic). You just used the wrong index:
>>> d.items()
[(1, [1, 2, 3, 4]), (2, [5, 6, 7])]
>>> d.items()[0]
(1, [1, 2, 3, 4])
>>> len(d.items()[0][1])
4
>>>for k,v in dict.iteritems():
k,len(v)
ans:-
(1, 4)
(2, 3)
or
>>>var1=[1,2,3,4]
>>>var2=[5,6,7]
>>>dict={1:var1,2:var2}
ans:-
>>>[len(v) for k,v in dict.iteritems()]
[4, 3]

How to make sense of this result?

I am new to Python. Here is a question I have about lists:
It is said that lists are mutable and tuples are immutable. But when I write the following:
L1 = [1, 2, 3]
L2 = (L1, L1)
L1[1] = 5
print L2
the result is
([1, 5, 3], [1, 5, 3])
instead of
([1, 2, 3], [1, 2, 3])
But L2 is a tuple and tuples are immutable. Why is it that when I change the value of L1, the value of L2 is also changed?
From the Python documentation (http://docs.python.org/reference/datamodel.html), note:
The value of an immutable container object that contains a reference to a mutable
object can change when the latter’s value is changed; however the container is
still considered immutable, because the collection of objects it contains cannot
be changed. So, immutability is not strictly the same as having an unchangeable
value, it is more subtle.
The tuple is immutable, but the list inside the tuple is mutable. You changed L1 (the list), not the tuple. The tuple contains two copies of L1, so they both show the change, since they are actually the same list.
If an object is "immutable", that doesn't automatically mean everything it touches is also immutable. You can put mutable objects inside immutable objects, and that won't stop you from continuing to mutate the mutable objects.
The tuple didn't get modified, it still contains the same duplicate references to list you gave it.
You modified a list (L1), not the tuple (or more precisely, not the reference to the list in the tuple).
For instance you would not have been able to do
L2[1] = 5
because tuples are immutable as you correctly state.
So the tuple wasn't changed, but the list that the tuple contained a reference to was modified (since both entries were references to the same list, both values in the output changed to 5). No value in the tuple was changed.
It may help if you think of reference as a "pointer" in this context.
EDIT (based on question by OP in comments below):
About references, lists and copies, maybe these examples will be helpful:
L=range(5)
s = (L, L[:]) # a reference to the original list and a copy
s
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])
then changing L[2]
L[2] = 'a'
gives:
s
([0, 1, 'a', 3, 4], [0, 1, 2, 3, 4]) # copy is not changed
Notice that the "2nd" list didn't change, since it contains a copy.
Now,
L=range(5)
we are creating two copies of the list and giving the references to the tuple
s = (L[:], L[:])
now
L[2] = 'a'
doesn't affect anything but the original list L
s
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])
Hope this is helpful.
You're right that tuples are immutable: L2 is an immutable tuple of two references to L1 (not, as it might first appear, a tuple of two lists), and L1 is not immutable. When you alter L1, you aren't altering L2, just the objects that L2 references.
Use deepcopy instead of = :
from copy import deepcopy
L2 = deepcopy(L1)
The tuple contains two references, each to the same list (not copies of the list, as you might have expected). Hence, changes in the list will still show up in the tuple (since the tuple contains only the references), but the tuple itself is not altered. Therefore, it's immutability is not violated.
Tuples being immutable means only one thing -- once you construct a tuple, it's impossible to modify it. Lists, on the other hand, can be added elements to, removed elements from. But, both tuples and lists are concerned with the elements they contain, but not with what those elements are.
In Python, and this has nothing to do with tuples or lists, when you add a simple value, like an int, it gets represented as is, but any complex value like a list, a tuple, or any other class-type object is always stored as reference.
If you were to convert your tuple to a set(), you'd get an error message that might surprise you, but given the above it should make sense:
>>> L=range(5)
>>> s = (L, L[:]) # a reference to the original list and a copy
>>> set(1, 2, s)
>>> set((1, 2, s))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
As values of a set must never change once they are added to the set, any mutable value contained inside the immutable tuple s raises TypeError.

What exactly are tuples in Python?

I'm following a couple of Pythone exercises and I'm stumped at this one.
# C. sort_last
# Given a list of non-empty tuples, return a list sorted in increasing
# order by the last element in each tuple.
# e.g. [(1, 7), (1, 3), (3, 4, 5), (2, 2)] yields
# [(2, 2), (1, 3), (3, 4, 5), (1, 7)]
# Hint: use a custom key= function to extract the last element form each tuple.
def sort_last(tuples):
# +++your code here+++
return
What is a Tuple? Do they mean a List of Lists?
The tuple is the simplest of Python's sequence types. You can think about it as an immutable (read-only) list:
>>> t = (1, 2, 3)
>>> print t[0]
1
>>> t[0] = 2
TypeError: tuple object does not support item assignment
Tuples can be turned into new lists by just passing them to list() (like any iterable), and any iterable can be turned into a new tuple by passing it to tuple():
>>> list(t)
[1, 2, 3]
>>> tuple(["hello", []])
("hello", [])
Hope this helps. Also see what the tutorial has to say about tuples.
Why are there separate tuple and list data types? (Python FAQ)
Python Tuples are Not Just Constant Lists
Understanding tuples vs. lists in Python
A tuple and a list is very similar. The main difference (as a user) is that a tuple is immutable (can't be modified)
In your example:
[(2, 2), (1, 3), (3, 4, 5), (1, 7)]
This is a list of tuples
[...] is the list
(2,2) is a tuple
A tuple is a sequence of immutable Python objects. Tuples are sequences, just like lists. The differences between tuples and lists are, the tuples cannot be changed unlike lists and tuples use parentheses, whereas lists use square brackets.
Creating a tuple is as simple as putting different comma-separated values. Optionally you can put these comma-separated values between parentheses also. For example −
tup1 = ('Dog', 'Cat', 2222, 555555);
tup2 = (10, 20, 30, 40, 50 );
tup3 = "a", "b", "c", "d";
The empty tuple is written as two parentheses containing nothing −
tup1 = ();
To write a tuple containing a single value you have to include a comma, even though there is only one value −
tup1 = (45,);
Like string indices, tuple indices start at 0, and they can be sliced, concatenated, and so on.
The best summary of the differences between lists and tuples I have read is this:
One common summary of these more interesting, if subtle, differences is that tuples are heterogeneous and lists are homogeneous. In other words: Tuples (generally) are sequences of different kinds of stuff, and you deal with the tuple as a coherent unit. Lists (generally) are sequences of the same kind of stuff, and you deal with the items individually.
From: http://news.e-scribe.com/397
Tuples are used to group related variables together. It's often more convenient to use a tuple rather than writing yet another single-use class. Granted, accessing their content by index is more obscure than a named member variable, but it's always possible to use 'tuple unpacking':
def returnTuple(a, b):
return (a, b)
a, b = returnTuple(1, 2)
In Python programming, a tuple is similar to a list. The difference between them is that we cannot change the elements of a tuple once it is assigned whereas in a list, elements can be changed.
data-types-in-python

Categories