Python defaultdict - python

I found something strange that I couldn't understand.
This is the case:
from collections import defaultdict
a = defaultdict(lambda: len(a))
This is just the part of the code, and the code has never defined 'a' above.
The questions are:
Is it possible to use defaultdict as is, not specifying the variable previously?
If possible, what is the meaning of that code?

Maybe it is best explained in an example:
>>> a = defaultdict(lambda: len(b))
>>> b = 'abcd'
>>> a[0]
4
As you can see, it is possible to use b in the lambda even though the b does not yet exist at that point. What is important is that b exists at the time when the lambda is executed. At that point, Python will look for a variable named b and use it.
Note also that the original code does not necessarily use length of the defaultdict itself. It simply evaluates whatever a is at that point. See this example:
>>> a = defaultdict(lambda: len(a))
>>> a['a']
0
>>> a['b']
1
So far, so good. But then rename some things:
>>> x = a
>>> a = []
>>> x['c']
0
>>> x['d']
0
Now the deaultdict is named x, but it does not use len(x). It still uses len(a). This caveat may become important if you sent the defaultdict to a function where a does not mean anything.

you are saying to default dict, when i try to do something with a key and it doesnt exist, use this lambda as the inital value for the key. since your lambda is using a (i.E the dict its self) and you say the length of it. It means when you perform operations using a key thats not in the dict then the dict will use the lambda instead or in this case the length of the dict as the value
from collections import defaultdict
a = defaultdict(lambda: len(a))
a['one'] += 5 #here dict length is 0 so value is 0 + 5 = 5
a['two'] += 2 #jere dict length is 1 so value is 1 + 2 = 3
a['three'] += 1 #here dict length is 2 so value is 2 + 1 = 3
print(a.items())
print(a['newval']) #here newval doesnt exist so will use default value which is length of dict I.E 3
OUTPUT
dict_items([('one', 5), ('two', 3), ('three', 3)])
3

Here's how defaultdict works. Say you have a dict of lists and you're setting values for keys that might not exist. In that case you'd do something like this:
d = dict()
if some_key not in d:
d[some_key] = list()
d[some_key].append(some_value)
defaultdict does this automatically for you by passing it a callable, e.g., int, list, set, which will call int() (default value 0), list() (default value empty list), and set() (default value empty set) respectively. Your lambda is also a callable, which returns integers, so you'll have a dict with int values. But the value you get from the expression will depend on the size of the dict.
Can you do a = defaultdict(lambda: len(a))?
Yes, you can. The lambda will not be executed until called which is when it'll look up the name a. Compare these two cases.
f = lambda: len(a)
a = defaultdict(f)
a[0] # this is when the lambda is called for the first time
But,
g = lambda: len(b)
g() # this will raise a NameError
b = defauldict(g)

Related

Checking if JSON object exists [duplicate]

This question's answers are a community effort. Edit existing answers to improve this post. It is not currently accepting new answers or interactions.
I wanted to test if a key exists in a dictionary before updating the value for the key.
I wrote the following code:
if 'key1' in dict.keys():
print "blah"
else:
print "boo"
I think this is not the best way to accomplish this task. Is there a better way to test for a key in the dictionary?
in tests for the existence of a key in a dict:
d = {"key1": 10, "key2": 23}
if "key1" in d:
print("this will execute")
if "nonexistent key" in d:
print("this will not")
Use dict.get() to provide a default value when the key does not exist:
d = {}
for i in range(10):
d[i] = d.get(i, 0) + 1
To provide a default value for every key, either use dict.setdefault() on each assignment:
d = {}
for i in range(10):
d[i] = d.setdefault(i, 0) + 1
or use defaultdict from the collections module:
from collections import defaultdict
d = defaultdict(int)
for i in range(10):
d[i] += 1
Use key in my_dict directly instead of key in my_dict.keys():
if 'key1' in my_dict:
print("blah")
else:
print("boo")
That will be much faster as it uses the dictionary's O(1) hashing as opposed to doing an O(n) linear search on a list of keys.
You can test for the presence of a key in a dictionary, using the in keyword:
d = {'a': 1, 'b': 2}
'a' in d # <== evaluates to True
'c' in d # <== evaluates to False
A common use for checking the existence of a key in a dictionary before mutating it is to default-initialize the value (e.g. if your values are lists, for example, and you want to ensure that there is an empty list to which you can append when inserting the first value for a key). In cases such as those, you may find the collections.defaultdict() type to be of interest.
In older code, you may also find some uses of has_key(), a deprecated method for checking the existence of keys in dictionaries (just use key_name in dict_name, instead).
You can shorten your code to this:
if 'key1' in my_dict:
...
However, this is at best a cosmetic improvement. Why do you believe this is not the best way?
For additional information on speed execution of the accepted answer's proposed methods (10 million loops):
'key' in mydict elapsed time 1.07 seconds
mydict.get('key') elapsed time 1.84 seconds
mydefaultdict['key'] elapsed time 1.07 seconds
Therefore using in or defaultdict are recommended against get.
I would recommend using the setdefault method instead. It sounds like it will do everything you want.
>>> d = {'foo':'bar'}
>>> q = d.setdefault('foo','baz') #Do not override the existing key
>>> print q #The value takes what was originally in the dictionary
bar
>>> print d
{'foo': 'bar'}
>>> r = d.setdefault('baz',18) #baz was never in the dictionary
>>> print r #Now r has the value supplied above
18
>>> print d #The dictionary's been updated
{'foo': 'bar', 'baz': 18}
A dictionary in Python has a get('key', default) method. So you can just set a default value in case there isn't any key.
values = {...}
myValue = values.get('Key', None)
Using the Python ternary operator:
message = "blah" if 'key1' in my_dict else "booh"
print(message)
Use EAFP (easier to ask forgiveness than permission):
try:
blah = dict["mykey"]
# key exists in dict
except KeyError:
# key doesn't exist in dict
See other Stack Overflow posts:
Using 'try' vs. 'if' in Python
Checking for member existence in Python
Check if a given key already exists in a dictionary
To get the idea how to do that we first inspect what methods we can call on dictionary.
Here are the methods:
d={'clear':0, 'copy':1, 'fromkeys':2, 'get':3, 'items':4, 'keys':5, 'pop':6, 'popitem':7, 'setdefault':8, 'update':9, 'values':10}
Python Dictionary clear() Removes all Items
Python Dictionary copy() Returns Shallow Copy of a Dictionary
Python Dictionary fromkeys() Creates dictionary from given sequence
Python Dictionary get() Returns Value of The Key
Python Dictionary items() Returns view of dictionary (key, value) pair
Python Dictionary keys() Returns View Object of All Keys
Python Dictionary pop() Removes and returns element having given key
Python Dictionary popitem() Returns & Removes Element From Dictionary
Python Dictionary setdefault() Inserts Key With a Value if Key is not Present
Python Dictionary update() Updates the Dictionary
Python Dictionary values() Returns view of all values in dictionary
The brutal method to check if the key already exists may be the get() method:
d.get("key")
The other two interesting methods items() and keys() sounds like too much of work. So let's examine if get() is the right method for us. We have our dict d:
d= {'clear':0, 'copy':1, 'fromkeys':2, 'get':3, 'items':4, 'keys':5, 'pop':6, 'popitem':7, 'setdefault':8, 'update':9, 'values':10}
Printing shows the key we don't have will return None:
print(d.get('key')) #None
print(d.get('clear')) #0
print(d.get('copy')) #1
We use that to get the information if the key is present or no.
But consider this if we create a dict with a single key:None:
d= {'key':None}
print(d.get('key')) #None
print(d.get('key2')) #None
Leading that get() method is not reliable in case some values may be None.
This story should have a happier ending. If we use the in comparator:
print('key' in d) #True
print('key2' in d) #False
We get the correct results.
We may examine the Python byte code:
import dis
dis.dis("'key' in d")
# 1 0 LOAD_CONST 0 ('key')
# 2 LOAD_NAME 0 (d)
# 4 COMPARE_OP 6 (in)
# 6 RETURN_VALUE
dis.dis("d.get('key2')")
# 1 0 LOAD_NAME 0 (d)
# 2 LOAD_METHOD 1 (get)
# 4 LOAD_CONST 0 ('key2')
# 6 CALL_METHOD 1
# 8 RETURN_VALUE
This shows that in compare operator is not just more reliable, but even faster than get().
The ways in which you can get the results are:
if your_dict.has_key(key) Removed in Python 3
if key in your_dict
try/except block
Which is better is dependent on 3 things:
Does the dictionary 'normally has the key' or 'normally does not have the key'.
Do you intend to use conditions like if...else...elseif...else?
How big is dictionary?
Read More: http://paltman.com/try-except-performance-in-python-a-simple-test/
Use of try/block instead of 'in' or 'if':
try:
my_dict_of_items[key_i_want_to_check]
except KeyError:
# Do the operation you wanted to do for "key not present in dict".
else:
# Do the operation you wanted to do with "key present in dict."
Python 2 only: (and Python 2.7 supports `in` already)
You can use the has_key() method:
if dict.has_key('xyz')==1:
# Update the value for the key
else:
pass
Just an FYI adding to Chris. B's (best) answer:
d = defaultdict(int)
Works as well; the reason is that calling int() returns 0 which is what defaultdict does behind the scenes (when constructing a dictionary), hence the name "Factory Function" in the documentation.
A Python dictionary has the method called __contains__. This method will return True if the dictionary has the key, else it returns False.
>>> temp = {}
>>> help(temp.__contains__)
Help on built-in function __contains__:
__contains__(key, /) method of builtins.dict instance
True if D has a key k, else False.
Another way of checking if a key exists using Boolean operators:
d = {'a': 1, 'b':2}
keys = 'abcd'
for k in keys:
x = (k in d and 'blah') or 'boo'
print(x)
This returns
>>> blah
>>> blah
>>> boo
>>> boo
Explanation
First, you should know that in Python, 0, None, or objects with zero length evaluate to False. Everything else evaluates to True. Boolean operations are evaluated left to right and return the operand not True or False.
Let's see an example:
>>> 'Some string' or 1/0
'Some string'
>>>
Since 'Some string' evaluates to True, the rest of the or is not evaluated and there is no division by zero error raised.
But if we switch the order 1/0 is evaluated first and raises an exception:
>>> 1/0 or 'Some string'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>>
We can use this for pattern for checking if a key exists.
(k in d and 'blah')
does the same as
if k in d:
'blah'
else:
False
This already returns the correct result if the key exists, but we want it to print 'boo' when it doesn't. So, we take the result and or it with 'boo'
>>> False or 'boo'
'boo'
>>> 'blah' or 'boo'
'blah'
>>>
You can use a for loop to iterate over the dictionary and get the name of key you want to find in the dictionary. After that, check if it exist or not using if condition:
dic = {'first' : 12, 'second' : 123}
for each in dic:
if each == 'second':
print('the key exists and the corresponding value can be updated in the dictionary')

How to increment a value (in defaultdict of defaultdicts)?

How to increment d['a']['b']['c'][1][2][3] if d is defaultdict of defaultdict without code dublication?
from collections import defaultdict
nested_dict_type = lambda: defaultdict(nested_dict_type)
nested_dict = nested_dict_type()
# incrementation
if type(nested_dict['a']['b']['c']['d'][1][2][3][4][5][6]) != int:
nested_dict['a']['b']['c']['d'][1][2][3][4][5][6] = 0
nested_dict['a']['b']['c']['d'][1][2][3][4][5][6] += 1 # ok, now it contains 1
Here we can see that we duplicated (in the code) a chain of keys 3 times.
Question: Is it possible to write a function inc that will take nested_dict['a']['b']...[6] and do the same job as above? So:
def inc(x):
if type(x) != int:
x = 0
x += 1
inc(nested_dict['a']['b']['c']['d'][1][2][3][4][5][6]) # ok, now it contains 1
Update (20 Aug 2018):
There is still no answer to the question. It's clear that there are options "how to do what I want", but the question is straightforward: there is "value", we pass it to a function, function modifies it. It looks that it's not possible.
Just a value, without any "additional keys", etc.
If it is so, can we make an answer more generic?
Notes:
What is defaultdict of defaultdicts - SO.
This question is not about "storing of integers in a defaultdict", so I'm not looking for a hierarchy of defaultdicts with an int type at the leaves.
Assume that type (int in the examples) is known in advance / can be even parametrized (including the ability to perform += operator) - the question is how to dereference the object, pass it for modification and store back in the context of defaultdict of defaultdicts.
Is the answer to this question related to the mutability? See example below:
Example:
def inc(x):
x += 1
d = {'a': int(0)}
inc(d['a'])
# d['a'] == 0, immutable
d = {'a': Int(0)}
inc(d['a'])
# d['a'] == 1, mutated
Where Int is:
class Int:
def __init__(self, value):
self.value = value
def __add__(self, v):
self.value += v
return self
def __repr__(self):
return str(self.value)
It's not exactly abut mutability, more about how assignment performs name binding.
When you do x = 0 in your inc function you bind a new object to the name x, and any connection between that name and the previous object bound to that name is lost. That doesn't depend on whether or not x is mutable.
But since x is an item in a mutable object we can achieve what you want by passing the parent mutable object to inc along with the key needed to access the desired item.
from collections import defaultdict
nested_dict_type = lambda: defaultdict(nested_dict_type)
nested_dict = nested_dict_type()
# incrementation
def inc(ref, key):
if not isinstance(ref[key], int):
ref[key] = 0
ref[key] += 1
d = nested_dict['a']['b']['c']['d'][1][2][3][4][5]
inc(d, 6)
print(d)
output
defaultdict(<function <lambda> at 0xb730553c>, {6: 1})
Now we aren't binding a new object, we're merely mutating an existing one, so the original d object gets updated correctly.
BTW, that deeply nested dict is a bit painful to work with. Maybe there's a better way to organize your data... But anyway, one thing that can be handy when working with deep nesting is to use lists or tuples of keys. Eg,
q = nested_dict
keys = 'a', 'b', 'c', 'd', 1, 2, 3, 4, 5
for k in keys:
q = q[k]
q now refers to nested_dict['a']['b']['c']['d'][1][2][3][4][5]
You can't have multiple default types with defaultdict. You have the following options:
Nested defaultdict of defaultdict objects indefinitely;
defaultdict of int objects, which likely won't suit your needs;
defaultdict of defaultdict down to a specific level with int defined for the last level, e.g. d = defaultdict(lambda: defaultdict(int)) for a single nesting;
Similar to (3), but for counting you can use collections.Counter instead, i.e. d = defaultdict(Counter).
I recommend the 3rd or 4th options if you are always going to go down to a set level. In other words, a scalar value will only be supplied at the nth level, where n is constant.
Otherwise, one manual option is to have a function perform the type-testing. In this case, try / except may be a good alternative. Here we also define a recursive algorithm to allow you to feed a list of keys rather than defining manual __getitem__ calls.
from collections import defaultdict
from functools import reduce
from operator import getitem
nested_dict_type = lambda: defaultdict(nested_dict_type)
d = nested_dict_type()
d[1][2] = 10
def inc(d_in, L):
try:
reduce(getitem, L[:-1], d_in)[L[-1]] += 1
except TypeError:
reduce(getitem, L[:-1], d_in)[L[-1]] = 1
inc(d, [1, 2])
inc(d, [1, 3])
print(d)
defaultdict({1: defaultdict({2: 11, 3: 1})})

Can't get function to add an item to a dictionnary [duplicate]

This question's answers are a community effort. Edit existing answers to improve this post. It is not currently accepting new answers or interactions.
I wanted to test if a key exists in a dictionary before updating the value for the key.
I wrote the following code:
if 'key1' in dict.keys():
print "blah"
else:
print "boo"
I think this is not the best way to accomplish this task. Is there a better way to test for a key in the dictionary?
in tests for the existence of a key in a dict:
d = {"key1": 10, "key2": 23}
if "key1" in d:
print("this will execute")
if "nonexistent key" in d:
print("this will not")
Use dict.get() to provide a default value when the key does not exist:
d = {}
for i in range(10):
d[i] = d.get(i, 0) + 1
To provide a default value for every key, either use dict.setdefault() on each assignment:
d = {}
for i in range(10):
d[i] = d.setdefault(i, 0) + 1
or use defaultdict from the collections module:
from collections import defaultdict
d = defaultdict(int)
for i in range(10):
d[i] += 1
Use key in my_dict directly instead of key in my_dict.keys():
if 'key1' in my_dict:
print("blah")
else:
print("boo")
That will be much faster as it uses the dictionary's O(1) hashing as opposed to doing an O(n) linear search on a list of keys.
You can test for the presence of a key in a dictionary, using the in keyword:
d = {'a': 1, 'b': 2}
'a' in d # <== evaluates to True
'c' in d # <== evaluates to False
A common use for checking the existence of a key in a dictionary before mutating it is to default-initialize the value (e.g. if your values are lists, for example, and you want to ensure that there is an empty list to which you can append when inserting the first value for a key). In cases such as those, you may find the collections.defaultdict() type to be of interest.
In older code, you may also find some uses of has_key(), a deprecated method for checking the existence of keys in dictionaries (just use key_name in dict_name, instead).
You can shorten your code to this:
if 'key1' in my_dict:
...
However, this is at best a cosmetic improvement. Why do you believe this is not the best way?
For additional information on speed execution of the accepted answer's proposed methods (10 million loops):
'key' in mydict elapsed time 1.07 seconds
mydict.get('key') elapsed time 1.84 seconds
mydefaultdict['key'] elapsed time 1.07 seconds
Therefore using in or defaultdict are recommended against get.
I would recommend using the setdefault method instead. It sounds like it will do everything you want.
>>> d = {'foo':'bar'}
>>> q = d.setdefault('foo','baz') #Do not override the existing key
>>> print q #The value takes what was originally in the dictionary
bar
>>> print d
{'foo': 'bar'}
>>> r = d.setdefault('baz',18) #baz was never in the dictionary
>>> print r #Now r has the value supplied above
18
>>> print d #The dictionary's been updated
{'foo': 'bar', 'baz': 18}
A dictionary in Python has a get('key', default) method. So you can just set a default value in case there isn't any key.
values = {...}
myValue = values.get('Key', None)
Using the Python ternary operator:
message = "blah" if 'key1' in my_dict else "booh"
print(message)
Use EAFP (easier to ask forgiveness than permission):
try:
blah = dict["mykey"]
# key exists in dict
except KeyError:
# key doesn't exist in dict
See other Stack Overflow posts:
Using 'try' vs. 'if' in Python
Checking for member existence in Python
Check if a given key already exists in a dictionary
To get the idea how to do that we first inspect what methods we can call on dictionary.
Here are the methods:
d={'clear':0, 'copy':1, 'fromkeys':2, 'get':3, 'items':4, 'keys':5, 'pop':6, 'popitem':7, 'setdefault':8, 'update':9, 'values':10}
Python Dictionary clear() Removes all Items
Python Dictionary copy() Returns Shallow Copy of a Dictionary
Python Dictionary fromkeys() Creates dictionary from given sequence
Python Dictionary get() Returns Value of The Key
Python Dictionary items() Returns view of dictionary (key, value) pair
Python Dictionary keys() Returns View Object of All Keys
Python Dictionary pop() Removes and returns element having given key
Python Dictionary popitem() Returns & Removes Element From Dictionary
Python Dictionary setdefault() Inserts Key With a Value if Key is not Present
Python Dictionary update() Updates the Dictionary
Python Dictionary values() Returns view of all values in dictionary
The brutal method to check if the key already exists may be the get() method:
d.get("key")
The other two interesting methods items() and keys() sounds like too much of work. So let's examine if get() is the right method for us. We have our dict d:
d= {'clear':0, 'copy':1, 'fromkeys':2, 'get':3, 'items':4, 'keys':5, 'pop':6, 'popitem':7, 'setdefault':8, 'update':9, 'values':10}
Printing shows the key we don't have will return None:
print(d.get('key')) #None
print(d.get('clear')) #0
print(d.get('copy')) #1
We use that to get the information if the key is present or no.
But consider this if we create a dict with a single key:None:
d= {'key':None}
print(d.get('key')) #None
print(d.get('key2')) #None
Leading that get() method is not reliable in case some values may be None.
This story should have a happier ending. If we use the in comparator:
print('key' in d) #True
print('key2' in d) #False
We get the correct results.
We may examine the Python byte code:
import dis
dis.dis("'key' in d")
# 1 0 LOAD_CONST 0 ('key')
# 2 LOAD_NAME 0 (d)
# 4 COMPARE_OP 6 (in)
# 6 RETURN_VALUE
dis.dis("d.get('key2')")
# 1 0 LOAD_NAME 0 (d)
# 2 LOAD_METHOD 1 (get)
# 4 LOAD_CONST 0 ('key2')
# 6 CALL_METHOD 1
# 8 RETURN_VALUE
This shows that in compare operator is not just more reliable, but even faster than get().
The ways in which you can get the results are:
if your_dict.has_key(key) Removed in Python 3
if key in your_dict
try/except block
Which is better is dependent on 3 things:
Does the dictionary 'normally has the key' or 'normally does not have the key'.
Do you intend to use conditions like if...else...elseif...else?
How big is dictionary?
Read More: http://paltman.com/try-except-performance-in-python-a-simple-test/
Use of try/block instead of 'in' or 'if':
try:
my_dict_of_items[key_i_want_to_check]
except KeyError:
# Do the operation you wanted to do for "key not present in dict".
else:
# Do the operation you wanted to do with "key present in dict."
Python 2 only: (and Python 2.7 supports `in` already)
You can use the has_key() method:
if dict.has_key('xyz')==1:
# Update the value for the key
else:
pass
Just an FYI adding to Chris. B's (best) answer:
d = defaultdict(int)
Works as well; the reason is that calling int() returns 0 which is what defaultdict does behind the scenes (when constructing a dictionary), hence the name "Factory Function" in the documentation.
A Python dictionary has the method called __contains__. This method will return True if the dictionary has the key, else it returns False.
>>> temp = {}
>>> help(temp.__contains__)
Help on built-in function __contains__:
__contains__(key, /) method of builtins.dict instance
True if D has a key k, else False.
Another way of checking if a key exists using Boolean operators:
d = {'a': 1, 'b':2}
keys = 'abcd'
for k in keys:
x = (k in d and 'blah') or 'boo'
print(x)
This returns
>>> blah
>>> blah
>>> boo
>>> boo
Explanation
First, you should know that in Python, 0, None, or objects with zero length evaluate to False. Everything else evaluates to True. Boolean operations are evaluated left to right and return the operand not True or False.
Let's see an example:
>>> 'Some string' or 1/0
'Some string'
>>>
Since 'Some string' evaluates to True, the rest of the or is not evaluated and there is no division by zero error raised.
But if we switch the order 1/0 is evaluated first and raises an exception:
>>> 1/0 or 'Some string'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>>
We can use this for pattern for checking if a key exists.
(k in d and 'blah')
does the same as
if k in d:
'blah'
else:
False
This already returns the correct result if the key exists, but we want it to print 'boo' when it doesn't. So, we take the result and or it with 'boo'
>>> False or 'boo'
'boo'
>>> 'blah' or 'boo'
'blah'
>>>
You can use a for loop to iterate over the dictionary and get the name of key you want to find in the dictionary. After that, check if it exist or not using if condition:
dic = {'first' : 12, 'second' : 123}
for each in dic:
if each == 'second':
print('the key exists and the corresponding value can be updated in the dictionary')

python sort a list of objects based on attributes in the order of the other list

I am working with Python list sort.
I have two lists: one is a list of integers, the other is a list of objects, and the second object list has the attribute id which is also an integer, I want to sort the object list based on the id attribute, in the order of the same id appears in the first list, well, this is an example:
I got a = [1,2,3,4,5]
and b = [o,p,q,r,s], where o.id = 2, p.id = 1, q.id = 3, r.id = 5, s.id = 4
and I want my list b to be sorted in the order of its id appears in list a, which is like this:
sorted_b = [p, o, q, s, r]
Of course, I can achieve this by using nested loops:
sorted_b = []
for i in a:
for j in b:
if j.id == i:
sorted_b.append(j)
break
but this is a classic ugly and non-Python way to solve a problem, I wonder if there is a way to solve this in a rather neat way, like using the sort method, but I don't know how.
>>> from collections import namedtuple
>>> Foo = namedtuple('Foo', 'name id') # this represents your class with id attribute
>>> a = [1,2,3,4,5]
>>> b = [Foo(name='o', id=2), Foo(name='p', id=1), Foo(name='q', id=3), Foo(name='r', id=5), Foo(name='s', id=4)]
>>> sorted(b, key=lambda x: a.index(x.id))
[Foo(name='p', id=1), Foo(name='o', id=2), Foo(name='q', id=3), Foo(name='s', id=4), Foo(name='r', id=5)]
This is a simple way to do it:
# Create a dictionary that maps from an ID to the corresponding object
object_by_id = dict((x.id, x) for x in b)
sorted_b = [object_by_id[i] for i in a]
If the list gets big, it's probably the fastest way, too.
You can do it with a list comprehension, but in general is it the same.
sorted_b = [ y for x in a for y in b if y.id == x ]
There is a sorted function in Python. It takes optional keyword argument cmp. You can pass there your customized function for sorting.
cmp definition from the docs:
custom comparison should return a negative, zero or positive number depending on whether the first argument is considered smaller than, equal to, or larger than the second argument
a = [1,2,3,4,5]
def compare(el1, el2):
if a.index(el1.id) < a.index(el2.id): return -1
if a.index(el1.id) > a.index(el2.id): return 1
return 0
sorted(b, cmp=compare)
This is more straightforward however I would encourage you to use the key argument as jamylak described in his answer, because it's more pythonic and in Python 3 the cmp is not longer supported.

How to get Python to tell equal integers apart

Have a bit of a problem distinguishing between identical integers.
In the following (which is obviously a trivial case) a, b, c are integers. I wish to create a dicionary, diction, which will contain {a: 'foo', b: 'bar', c: 'baz'}
diction = {}
for i in (a, b, c):
j = ('foo', 'bar', 'baz')[(a, b, c).index(i)]
diction[i] = j
All runs very nicely until, for example, a and b are the same: the third line will give index 0 for both a and b, resulting in j = 'foo' for each case.
I know lists can be copied by
list_a = [1, 2, 3]
list_b = list(list_a)
or
list_b = list_a[:]
So, is there any way of maybe doing this with my identical integers?
(I tried making one a float, but the value remains the same , so that doesn't work.)
To create a dictionary from two different iterables, you can use the following code:
d = dict(zip((a, b, c), ('foo', 'bar', 'baz')))
where zip is used to combine both iterables in a list of tuples that can be passed to the dictionary constructor.
Note that if a==b, then the 'foo' will be overwritten with 'bar', since the values are added to the dictionary in the same order they are in the iterable as if you were using this code:
d[a] = 'foo'
d[b] = 'bar'
d[c] = 'baz'
This is just the standard behaviour of a dictionary, when a new value is assigned to a key that is already known, the value is overwritten.
If you prefer to keep all values in a list, then you can use a collections.defaultdict as follows:
from collections import defaultdict
d = defaultdict(list)
for key, value in zip((a, b, c), ('foo', 'bar', 'baz')):
d[key].append(value)
You can't distinguish between identical objects.
You can tell them apart if they do not fall between -5 and 256
See also "is" operator behaves unexpectedly with integers
http://docs.python.org/c-api/int.html
The current implementation keeps an array of integer objects for all
integers between -5 and 256, when you create an int in that range you
actually just get back a reference to the existing object. So it
should be possible to change the value of 1. I suspect the behaviour
of Python in this case is undefined. :-)
In [30]: a = 257
In [31]: a is 257
Out[31]: False
In [32]: a = 256
In [33]: a is 256
Out[33]: True
You may have to roll your own dictionary like object that implements this sort of behavior though... and it still wouldn't be able to do anything between -5 and 256. I'd need to do more digging to be sure though.
If a and b have the same value then you can't expect them to point to different positions in dictionary if used as keys. Key values in dictionaries must be unique.
Also if you have two sequences the simplest way to make a dictionary out of them is to zip them together:
tup = (a,b,c)
val = ('foo', 'bar', 'baz')
diction = dict(zip(tup, val))
All of the answers so far are correct - identical keys can't be re-used in a dictionary. If you absolutely have to try to do something like this, but can't ensure that a, b, and c have distinct values you could try something like this:
d = dict(zip((id(k) for k in (a,b,c)), ('foo', 'bar', 'baz')))
When you go to look up your values though, you'll have to remember to do so like this:
d[id(a)]
That might help, but I am not certain what you're actually after here.

Categories

Resources