Can someone help me read this Python dictionary-tuples?
I am new to python and I can't get much out of it
Grammar = {'AB':('S', 'B'), 'BB':'A', 'a':'A', 'b':'B'}
Note:
The grammar is the grammar of a Context Free Grammar.
To convert the dictionary into what you want you can do something like this:
>>> from collection import defaultdict
>>> grammar = {'AB':('S', 'B'), 'BB':'A', 'a':'A', 'b':'B'}
>>> tmp_result = defaultdict(list)
>>> def tuplify(val):
... if not isinstance(val, tuple):
... val = (val,)
... return val
...
>>> for key, value in grammar.items():
... values = tuplify(value)
... for val in values:
... tmp_result[val].append(key)
...
>>> tmp_result
defaultdict(<type 'list'>, {'A': ['a', 'BB'], 'S': ['AB'], 'B': ['AB', 'b']})
>>> result = {key:tuple(val) for key, val in tmp_result.items()}
>>> result
{'A': ('a', 'BB'), 'S': ('AB',), 'B': ('AB', 'b')}
Where the class collections.defaultdict is a dict-like class, which uses a factory to create a default value when the key is missing. For example writing:
>>> D = defaultdict(list)
>>> D[5].append(3)
>>> D[5]
[3]
Can be written using normal dicts like:
>>> D = {}
>>> if 5 in D: # key present, use that value
... val = D[5]
... else: # otherwise create a default value and sets it
... val = list()
... D[5] = val
...
>>> val.append(3)
>>> D[5]
[3]
The "factory" passed to defaultdict(factory) can be any callable that doesn't receive arguments, for example:
>>> n = 0
>>> def factory():
... global n
... print('Factory called!')
... n += 1
... return n #returns numbers 1, 2, 3, 4, ...
...
>>> D = defaultdict(factory)
>>> D[0]
Factory called!
1
>>> D[0] # the keys exists, thus the factory is not called.
1
>>> D[1]
Factory called!
2
>>> D[1]
2
Related
Is there a way to get the original/consistent list of keys from defaultdict even when non existing keys were requested?
from collections import defaultdict
>>> d = defaultdict(lambda: 'default', {'key1': 'value1', 'key2' :'value2'})
>>>
>>> d.keys()
['key2', 'key1']
>>> d['bla']
'default'
>>> d.keys() # how to get the same: ['key2', 'key1']
['key2', 'key1', 'bla']
You have to exclude. the keys that has the default value!
>>> [i for i in d if d[i]!=d.default_factory()]
['key2', 'key1']
Time comparison with method suggested by Jean,
>>> def funct(a=None,b=None,c=None):
... s=time.time()
... eval(a)
... print time.time()-s
...
>>> funct("[i for i in d if d[i]!=d.default_factory()]")
9.29832458496e-05
>>> funct("[k for k,v in d.items() if v!=d.default_factory()]")
0.000100135803223
>>> ###storing the default value to a variable and using the same in the list comprehension reduces the time to a certain extent!
>>> defa=d.default_factory()
>>> funct("[i for i in d if d[i]!=defa]")
8.82148742676e-05
>>> funct("[k for k,v in d.items() if v!=defa]")
9.79900360107e-05
[key for key in d.keys() if key != 'default']
default_factory() is a callable and need not return the same value each time!
>>> from collections import defaultdict
>>> from random import random
>>> d = defaultdict(lambda: random())
>>> d[1]
0.7411252345322932
>>> d[2]
0.09672701444816645
>>> d.keys()
dict_keys([1, 2])
>>> d.default_factory()
0.06277993247659297
>>> d.default_factory()
0.4388136209046052
>>> d.keys()
dict_keys([1, 2])
>>> [k for k in d.keys() if d[k] != d.default_factory()]
[1, 2]
is there any way to dynamically create missing keys if i want to want to set a variable in a subdictionary.
essentially I want to create any missing keys and set my value.
self.portdict[switchname][str(neighbor['name'])]['local']['ports'] = []
currently i'm doing it but its messy:
if not switchname in self.portdict:
self.portdict[switchname] = {}
if not str(neighbor['name']) in self.portdict[switchname]:
self.portdict[switchname][str(neighbor['name'])] = {}
if not 'local' in self.portdict[switchname][str(neighbor['name'])]:
self.portdict[switchname][str(neighbor['name'])]['local'] = {}
if not 'ports' in self.portdict[switchname][str(neighbor['name'])]['local']:
self.portdict[switchname][str(neighbor['name'])]['local']['ports'] = []
Is there any way to do this in one or two lines instead?
This is easier to do without recursion:
def set_by_path(dct, path, value):
ipath = iter(path)
p_last = next(ipath)
try:
while True:
p_next = next(ipath)
dct = dct.setdefault(p_last, {})
p_last = p_next
except StopIteration:
dct[p_last] = value
And a test case:
d = {}
set_by_path(d, ['foo', 'bar', 'baz'], 'qux')
print d # {'foo': {'bar': {'baz': 'qux'}}}
If you want to have it so you don't need a function, you can use the following defaultdict factory which allows you to nest things arbitrarily deeply:
from collections import defaultdict
defaultdict_factory = lambda : defaultdict(defaultdict_factory)
d = defaultdict_factory()
d['foo']['bar']['baz'] = 'qux'
print d
Use collections.defaultdict
self.portdict = defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: []))))
I've run into a similar problem in the past. I found that defaultdict was the right answer for me—but writing the super long definitions (like the one in #o11c's answer or #Apero's answer) was no good. Here's what I came up with instead:
from collections import defaultdict
from functools import partial
def NestedDefaultDict(levels, baseFn):
def NDD(lvl):
return partial(defaultdict, NDD(lvl-1)) if lvl > 0 else baseFn
return defaultdict(NDD(levels-1))
This creates a dictionary with levels of nested dictionaries. So if you have levels=3, then you need 3 keys to access the bottom-level value. The second argument is a function which is used to create the bottom-level values. Something like list or lambda: 0 or even dict would work well.
Here's an example of using the "automatic" keys with 4 levels, and list as the default function:
>>> x = NestedDefaultDict(4, list)
>>> x[1][2][3][4].append('hello')
>>> x
defaultdict(<functools.partial object at 0x10b5c22b8>, {1: defaultdict(<functools.partial object at 0x10b5c2260>, {2: defaultdict(<functools.partial object at 0x10b5c2208>, {3: defaultdict(<type 'list'>, {4: ['hello']})})})})
I think that's basically what you'd want for the case in your question. Your 4 "levels" are switch-name, neighbor-name, local, & ports—and it looks like you want a list at the bottom-level to store your ports.
Another example using 2 levels and lambda: 0 as the default:
>>> y = NestedDefaultDict(2, lambda: 0)
>>> y['foo']['bar'] += 7
>>> y['foo']['baz'] += 10
>>> y['foo']['bar'] += 1
>>> y
defaultdict(<functools.partial object at 0x1021f1310>, {'foo': defaultdict(<function <lambda> at 0x1021f3938>, {'baz': 10, 'bar': 8})})
Have a close look to collections.defaultdict:
from collections import defaultdict
foo = defaultdict(dict)
foo['bar'] = defaultdict(dict)
foo['bar']['baz'] = defaultdict(dict)
foo['bar']['baz']['aaa'] = 1
foo['bor'] = 0
foo['bir'] = defaultdict(list)
foo['bir']['biz'].append(1)
foo['bir']['biz'].append(2)
print foo
defaultdict(<type 'dict'>, {'bir': defaultdict(<type 'list'>, {'biz': [1, 2]}), 'bor': 0, 'bar': defaultdict(<type 'dict'>, {'baz': defaultdict(<type 'dict'>, {'aaa': 1})})})
I know you can use setdefault(key, value) to set default value for a given key, but is there a way to set default values of all keys to some value after creating a dict ?
Put it another way, I want the dict to return the specified default value for every key I didn't yet set.
You can replace your old dictionary with a defaultdict:
>>> from collections import defaultdict
>>> d = {'foo': 123, 'bar': 456}
>>> d['baz']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'baz'
>>> d = defaultdict(lambda: -1, d)
>>> d['baz']
-1
The "trick" here is that a defaultdict can be initialized with another dict. This means
that you preserve the existing values in your normal dict:
>>> d['foo']
123
Use defaultdict
from collections import defaultdict
a = {}
a = defaultdict(lambda:0,a)
a["anything"] # => 0
This is very useful for case like this,where default values for every key is set as 0:
results ={ 'pre-access' : {'count': 4, 'pass_count': 2},'no-access' : {'count': 55, 'pass_count': 19}
for k,v in results.iteritems():
a['count'] += v['count']
a['pass_count'] += v['pass_count']
In case you actually mean what you seem to ask, I'll provide this alternative answer.
You say you want the dict to return a specified value, you do not say you want to set that value at the same time, like defaultdict does. This will do so:
class DictWithDefault(dict):
def __init__(self, default, **kwargs):
self.default = default
super(DictWithDefault, self).__init__(**kwargs)
def __getitem__(self, key):
if key in self:
return super(DictWithDefault, self).__getitem__(key)
return self.default
Use like this:
d = DictWIthDefault(99, x=5, y=3)
print d["x"] # 5
print d[42] # 99
42 in d # False
d[42] = 3
42 in d # True
Alternatively, you can use a standard dict like this:
d = {3: 9, 4: 2}
default = 99
print d.get(3, default) # 9
print d.get(42, default) # 99
defaultdict can do something like that for you.
Example:
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> d
defaultdict(<class 'list'>, {})
>>> d['new'].append(10)
>>> d
defaultdict(<class 'list'>, {'new': [10]})
Is this what you want:
>>> d={'a':1,'b':2,'c':3}
>>> default_val=99
>>> for k in d:
... d[k]=default_val
...
>>> d
{'a': 99, 'b': 99, 'c': 99}
>>>
>>> d={'a':1,'b':2,'c':3}
>>> from collections import defaultdict
>>> d=defaultdict(lambda:99,d)
>>> d
defaultdict(<function <lambda> at 0x03D21630>, {'a': 1, 'c': 3, 'b': 2})
>>> d[3]
99
Not after creating it, no. But you could use a defaultdict in the first place, which sets default values when you initialize it.
You can use the following class. Just change zero to any default value you like. The solution was tested in Python 2.7.
class cDefaultDict(dict):
# dictionary that returns zero for missing keys
# keys with zero values are not stored
def __missing__(self,key):
return 0
def __setitem__(self, key, value):
if value==0:
if key in self: # returns zero anyway, so no need to store it
del self[key]
else:
dict.__setitem__(self, key, value)
So I'm writing a class that extends a dictionary which right now uses a method "dictify" to transform itself into a dict. What I would like to do instead though is change it so that calling dict() on the object results in the same behavior, but I don't know which method to override. Is this not possible, or I am I missing something totally obvious? (And yes, I know the code below doesn't work but I hope it illustrates what I'm trying to do.)
from collections import defaultdict
class RecursiveDict(defaultdict):
'''
A recursive default dict.
>>> a = RecursiveDict()
>>> a[1][2][3] = 4
>>> a.dictify()
{1: {2: {3: 4}}}
'''
def __init__(self):
super(RecursiveDict, self).__init__(RecursiveDict)
def dictify(self):
'''Get a standard dictionary of the items in the tree.'''
return dict([(k, (v.dictify() if isinstance(v, dict) else v))
for (k, v) in self.items()])
def __dict__(self):
'''Get a standard dictionary of the items in the tree.'''
print [(k, v) for (k, v) in self.items()]
return dict([(k, (dict(v) if isinstance(v, dict) else v))
for (k, v) in self.items()])
EDIT: To show the problem more clearly:
>>> b = RecursiveDict()
>>> b[1][2][3] = 4
>>> b
defaultdict(<class '__main__.RecursiveDict'>, {1: defaultdict(<class '__main__.RecursiveDict'>, {2: defaultdict(<class '__main__.RecursiveDict'>, {3: 4})})})
>>> dict(b)
{1: defaultdict(<class '__main__.RecursiveDict'>, {2: defaultdict(<class '__main__.RecursiveDict'>, {3: 4})})}
>>> b.dictify()
{1: {2: {3: 4}}}
I want dict(b) to be same as b.dictify()
Nothing wrong with your approach, but this is similar to the Autovivification feature of Perl, which has been implemented in Python in this question. Props to #nosklo for this.
class RecursiveDict(dict):
"""Implementation of perl's autovivification feature."""
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
>>> a = RecursiveDict()
>>> a[1][2][3] = 4
>>> dict(a)
{1: {2: {3: 4}}}
EDIT
As suggested by #Rosh Oxymoron, using __missing__ results in a more concise implementation. Requires Python >= 2.5
class RecursiveDict(dict):
"""Implementation of perl's autovivification feature."""
def __missing__(self, key):
value = self[key] = type(self)()
return value
Do you want just to print it like a dict ? use this:
from collections import defaultdict
class RecursiveDict(defaultdict):
'''
A recursive default dict.
>>> a = RecursiveDict()
>>> a[1][2][3] = 4
>>> a.dictify()
{1: {2: {3: 4}}}
>>> dict(a)
{1: {2: {3: 4}}}
'''
def __init__(self):
super(RecursiveDict, self).__init__(RecursiveDict)
def dictify(self):
'''Get a standard dictionary of the items in the tree.'''
return dict([(k, (v.dictify() if isinstance(v, dict) else v))
for (k, v) in self.items()])
def __dict__(self):
'''Get a standard dictionary of the items in the tree.'''
print [(k, v) for (k, v) in self.items()]
return dict([(k, (dict(v) if isinstance(v, dict) else v))
for (k, v) in self.items()])
def __repr__(self):
return repr(self.dictify())
Maybe you are looking for __missing__ :
class RecursiveDict(dict):
'''
A recursive default dict.
>>> a = RecursiveDict()
>>> a[1][2][3] = 4
>>> a
{1: {2: {3: 4}}}
>>> dict(a)
{1: {2: {3: 4}}}
'''
def __missing__(self, key):
self[key] = self.__class__()
return self[key]
edit: As ironchefpython pointed out in comments, this isn't actually doing what I thought it did, as in my example b[1] is still a RecursiveDict. This may still be useful, as you essentially get an object pretty similar Rob Cowie's answer, but it is built on defaultdict.
You can get the behavior you want (or something very similar) by overriding __repr__, check this out:
class RecursiveDict(defaultdict):
def __init__(self):
super(RecursiveDict, self).__init__(RecursiveDict)
def __repr__(self):
return repr(dict(self))
>>> a = RecursiveDict()
>>> a[1][2][3] = 4
>>> a # a looks like a normal dict since repr is overridden
{1: {2: {3: 4}}}
>>> type(a)
<class '__main__.RecursiveDict'>
>>> b = dict(a)
>>> b # dict(a) gives us a normal dictionary
{1: {2: {3: 4}}}
>>> b[5][6] = 7 # obviously this won't work anymore
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 5
>>> type(b)
<type 'dict'>
There may be a better way to get to a normal dictionary view of the defaultdict than dict(self) but I couldn't find one, comment if you know how.
You can't do it.
I deleted my previous answer, because I found after looking at the source code, that if you call dict(d) on a d that is a subclass of dict, it makes a fast copy of the underlying hash in C, and returns a new dict object.
Sorry.
If you really want this behavior, you'll need to create a RecursiveDict class that doesn't inherit from dict, and implement the __iter__ interface.
You need to override __iter__.
def __iter__(self):
return iter((k, (v.dictify() if isinstance(v, dict) else v))
for (k, v) in self.items())
Instead of self.items(), you should use self.iteritems() on Python 2.
Edit: OK, This seems to be your problem:
>>> class B(dict): __iter__ = lambda self: iter(((1, 2), (3, 4)))
...
>>> b = B()
>>> dict(b)
{}
>>> class B(list): __iter__ = lambda self: iter(((1, 2), (3, 4)))
...
>>> b = B()
>>> dict(b)
{1: 2, 3: 4}
So this method doesn't work if the object you're calling dict() on is a subclass of dict.
Edit 2: To be clear, defaultdict is a subclass of dict. dict(a_defaultdict) is still a no-op.
Once you have your dictify function working just do
dict = dictify
Update:
Here is a short way to have this recursive dict:
>>> def RecursiveDict():
... return defaultdict(RecursiveDict)
Then you can:
d[1][2][3] = 5
d[1][2][4] = 6
>>> d
defaultdict(<function ReturnsRecursiveDict at 0x7f3ba453a5f0>, {1: defaultdict(<function ReturnsRecursiveDict at 0x7f3ba453a5f0>, {2: defaultdict(<function ReturnsRecursiveDict at 0x7f3ba453a5f0>, {3: 5, 4: 6})})})
I don't see a neat way to implement dictify.
I know how python dictionaries store key: value tuples. In the project I'm working on, I'm required to store key associated with a value that's a list.
ex:
key -> [0,2,4,5,8]
where,
key is a word from text file
the list value contains ints that stand for the DocIDs in which the word occurs.
as soon as I find the same word in another doc, i need to append that DocID to the list.
How can I achieve this?
You can use defauldict, like this:
>>> import collections
>>> d = collections.defaultdict(list)
>>> d['foo'].append(9)
>>> d
defaultdict(<type 'list'>, {'foo': [9]})
>>> d['foo'].append(90)
>>> d
defaultdict(<type 'list'>, {'foo': [9, 90]})
>>> d['bar'].append(5)
>>> d
defaultdict(<type 'list'>, {'foo': [9, 90], 'bar': [5]})
This would be a good place to use defaultdict
from collections import defaultdict
docWords = defaultdict(set)
for docID in allTheDocIDs:
for word in wordsOfDoc(docID):
docWords[word].add(docID)
you can use a list instead of a set if you have to
This post was helpful for me to solve a problem I had in dynamically creating variable keys with lists of data attached. See below:
import collections
d = collections.defaultdict(list)
b = collections.defaultdict(list)
data_tables = ['nodule_data_4mm_or_less_counts','nodule_data_4to6mm_counts','nodule_data_6to8mm_counts','nodule_data_8mm_or_greater_counts']
for i in data_tables:
data_graph = con.execute("""SELECT ACC_Count, COUNT(Accession) AS count
FROM %s
GROUP BY ACC_Count"""%i)
rows = data_graph.fetchall()
for row in rows:
d[i].append(row[0])
b[i].append(row[1])
print d['nodule_data_4mm_or_less_counts']
print b['nodule_data_4mm_or_less_counts']
Which outputs the data lists for each key and then can be changed to a np.array for plotting etc.
>>>[4201, 1052, 418, 196, 108, 46, 23, 12, 11, 8, 7, 2, 1]
>>>[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]
Something like this?
word = 'something'
l = [0,2,4,5,8]
myDict = {}
myDict[word] = l
#Parse some more
myDict[word].append(DocID)
I once wrote a helper class to make #Vinko Vrsalovic`s answer easier to use:
class listdict(defaultdict):
def __init__(self):
defaultdict.__init__(self, list)
def update(self, E=None, **F):
if not E is None:
try:
for k in E.keys():
self[k].append(E[k])
except AttributeError:
for (k, v) in E:
self[k].append(v)
for k in F:
self[k].append(F[k])
This can be used like this:
>>> foo = listdict()
>>> foo[1]
[]
>>> foo.update([(1, "a"), (1, "b"), (2, "a")])
>>> foo
defaultdict(<type 'list'>, {1: ['a', 'b'], 2: ['a']})
If i get your question right,You can try this ,
>>> a=({'a':1,'b':2});
>>> print a['a']
1
>>> a.update({'a':3})
>>> print a['a']
3
>>> a.update({'c':4})
>>> print a['c']
4
This will work with older versions of python