Dictionary of pair in python - python

I am new to python and was trying to make a dict of pairs in python.
What I would have done in c++ is
dist[make_pair(a,b)]=1
I am not sure how I can do the same in python
Edit
What I basically want to do is to map a pair of two integers to some value-
for example-
(1,2) -> 1
(1,3) -> 2
(2,1) ->3
I want to map pairs to some integer value

You can use the data structure "tuple" as a key in the dictionary. If you want to define a function that returns a n-tuple given n inputs, you can do that also.
a = 4
b = 5
dict_example = dict()
dict_example[(a,b)] = 1
print dict_example[(a,b)]
This prints the value of key (a,b), which is 1

To create an element having the tuple (a,b) as key, and 1 as a value, you just have to do :
new_dict = {(a,b) : 1}
If such a dict already exist, and you want to add the pair a,b as a key and 1 as a value, you have to do :
existing_dict[(a,b)] = 1
You can also use existing_dict[a,b] = 1 as Duncan pointed out.

I guess you tried using an array as a dict key, like:
>>> d = {}
>>> pair = [0, 1]
>>> d[pair] = 'foo'
TypeError: unhashable type: 'list'
Ok, what is that? Python dict keys must not be mutable. They can be numbers, strings and other hashable types - you can't use mutable types like lists, dicts and other mutable collections.
There is a collection that is very like a list but is not mutable: the tuple.
>>> d[tuple(pair)] = 'foo'
>>> d
{(1, 2): 'foo'}
As you can see, the literal for a tuple is (v1, v2, ..., vN). In places where it is not ambiguous, you can even omit the parenthesis:
>>> pair = 0, 1
>>> pair
(0, 1)
More than once I was bit by this when I left a trailing comma while refactoring code:
>>> x = 1, # I meant x = 1
>>> x
(1,)
That is the literal for a tuple with just 1 element.

Related

Why is the dictionary key not changing

a = (1,2)
b = {a:1}
print(b[a]) # This gives 1
a = (1,2,3)
print(b[a]) # This gives error but b[(1,2)] is working fine
What I understood is python doesn't run garbage collector after a is changed to (1,2,3) as the tuple (1,2,3) is created as a new object and the tuple (1,2) is still being referenced in b.
What I didn't understood is why 'b' doesn't change the key after 'a' is changed
b = {a:1} creates a dictionary with the value of a as a key and 1 as a value. When you assign a value to a, you create a new value, and b retrain the old value as its key.
The following example, using id, may illustrate it:
>>> a = (1,2)
>>> b = {a:1}
>>> id(a)
139681226321288
>>> a = (1,2,3)
>>> id(a)
139681416297520
>>> id(b.keys()[0])
139681226321288
Integers, floats, strings, tuples in python are immutable. A dictionary would allow only those keys which would be hashable (immutable built-in objects are hashable). As #Mureinik correctly specified the reason behind the cause, I would give you another example where you can mutate the data by the process you followed above.
>>> l = [1,2,3]
>>> b = {'3' : l}
>>> b
{'3': [1, 2, 3]}
>>> l.append(5)
>>> l
[1, 2, 3, 5]
>>> b
{'3': [1, 2, 3, 5]}
But you cannot change the keys of a dictionary as they are hashed (only values can be updated). You either have to delete existing key-value pair or add new pair.

How does this Lambda Expression work?

I'm familiar with simple lambda expressions. However I have this lambda expression in a book.
dd_pair = defaultdict(lambda: [0,0])
dd_pair[2][1] = 1 #now dd_pair contains {2: [0,1]}
I didn't declare any input variables, which is not how I learned Lambdas.
The previous example from the book has
dd_dict = defaultdict(dict)
dd_dict["Joel"]["City"] = "Seattle"
#this produces {"Joel" : { "City": "Seattle"}}
This makes sense, The Key is Joel, the nested Key is City, and the value is Seattle.
My two part question is, how does a lambda work with no input variables? and should I assume that the dd_pair[2][1] is to create a key 2 and at index 1 of the list set the value =1?
lambda: [0, 0] is exactly the same as:
def zero_pair():
return [0, 0]
that is, it is a function that takes no arguments and returns a len 2 array with the two entries set to 0. defaultdict takes a callable that takes no arguments and returns the value for a missing key so your second example (dd_pair = defaultdict(lambda: [0,0])) is the same as:
dd_pair = defaultdict(zero_pair)
Now, a dictionary in Python can take any value for its key (as long as they are hashable).
{0: 'integer', '0': 'string'}[0] # 'integer'
So when we index into dd_pair with a two, since the dictionary doesn't have any key at 2 our lambda (which is equivalent to zero_pair) is called and returns a list with two zeros in it. We then set the second element in that list to 1, mutating the list in place.
So yes, you're pretty much spot on when you say:
should I assume that the dd_pair[2][1] is to create a key 2 and at index 1 of the list set the value = 1

max value of a list filled with named tuples

I create a list filled with named tuples:
from collections import namedtuple
Point = namedtuple('Point', 'x y')
a = Point(5,4)
b = Point(8,3)
tab = [a,b]
print tab
>>[Point(x=5, y=4), Point(x=8, y=3)]
I would like to have the max of the x values in the list 'tab'
max(tab.x)
>> 8
Try like this,
>>> max(tab, key=lambda k: k.x)
Point(x=8, y=3)
>>> max(tab, key=lambda k: k.x).x
8
The optional key argument specifies a one-argument ordering function
like that used for list.sort(). The key argument, if supplied, must be
in keyword form (for example, max(a,b,c,key=func)).
https://docs.python.org/2/library/functions.html#max
You may simple do it as :
print max([i.x for i in tab])
However it may not be the best approach to do the same.

Two Basic Python Dictionary Questions

Question 1.)
for a,a in dict.items():
print a
Why does the above print the value, and if i print a,a - obviously both values are printed twice. If I had typed for a,b I would be iterating (key,value) pairs so I would logically think I am now iterating over (key,key) pairs and would therefore print key rather than value. Sorry for the basic questions just playing around in interpreter and trying to figure stuff out.
Question 2.)
for key,value in dict.items():
print "%s is the key that corresponds to the value %s"%(key,value)
The above example makes sense to me, but why does:
for key in dict.items():
print "%s is the key that corresponds to the value %s"%(key)
produce the same result? Is it because even though we aren't unpacking the tuple into two separate variables in the for statement, it is returned as (key,value) in the string formatter through the key call - basically making %(key) = (key,value)?
Q1:
Consider the following:
>>> d = {"a": 1, "b": 2, "c": 3}
>>> xs = d.items()
>>> a, a = xs[0]
>>> print a, a
1 1
This is effectively what is happening. You are unpacking each (key, value) pair into (a, a) effectively ending up with (value, value). The reference to the key is lost.
This is the same as:
>>> a, a = 1, 2
>>> print a, a
2, 2
What happens here in the interpreter during the unpacking:
a becomes 1.
a becomes 2.
Q2:
Consider the following:
>>> a, b = ("a", 1)
>>> print "%s=%s" % (a, b)
a, 1
>>> x = ("a", 1)
>>> print "%s=%s" % x
a, 1
The two are effectively the same. Since your string interpolation is expecting a tuple of two both (a, b) and x (a tuple of 2 values) effectively satisfies this.
You right. key is now tuple (k,v) and "..."% expect tuple with arguments. And ((k,v)) ( in ".." % ((k,v)) ) doesn't give "tuple in tuple" but only "single-level" tuple - like (1) doesn't give tuple but integer 1 - so you have "..." % (k,v)
d={1:2,4:5,6:7,8:8}
for a,a in d.items():
print(a,a)
In dictionary ,
a,a runs with (key,value)
And ends up with (value,value)
Output:
Starts with (1,2) ends with (2,2)
Starts with (4,5) ends with (5,5)
Starts with (6,7) ends with (7,7)
Starts with (8,8) ends with (8,8)
So Actual Output:
2 2
5 5
7 7
8 8

Python dictionary creation error

I am trying to create a Python dictionary from a stored list. This first method works
>>> myList = []
>>> myList.append('Prop1')
>>> myList.append('Prop2')
>>> myDict = dict([myList])
However, the following method does not work
>>> myList2 = ['Prop1','Prop2','Prop3','Prop4']
>>> myDict2 = dict([myList2])
ValueError: dictionary update sequence element #0 has length 3; 2 is required
So I am wondering why the first method using append works but the second method doesn't work? Is there a difference between myList and myList2?
Edit
Checked again myList2 actually has more than two elements. Updated second example to reflect this.
You're doing it wrong.
The dict() constructor doesn't take a list of items (much less a list containing a single list of items), it takes an iterable of 2-element iterables. So if you changed your code to be:
myList = []
myList.append(["mykey1", "myvalue1"])
myList.append(["mykey2", "myvalue2"])
myDict = dict(myList)
Then you would get what you expect:
>>> myDict
{'mykey2': 'myvalue2', 'mykey1': 'myvalue1'}
The reason that this works:
myDict = dict([['prop1', 'prop2']])
{'prop1': 'prop2'}
Is because it's interpreting it as a list which contains one element which is a list which contains two elements.
Essentially, the dict constructor takes its first argument and executes code similar to this:
for key, value in myList:
print key, "=", value

Categories