For a lot of objects before calling .append() I do something like:
if not d.get('turns'):
d['turns'] = []
Is there a oneliner in Python to do this?
After some answers, here's my kind of code:
d = json.loads(str(self.data))
if not d.get('turns'):
d['turns'] = []
d['turns'].append({
'date': time_turn,
'data': data
})
You can use defaultdict:
from collections import defaultdict
d = defaultdict(list)
d['turns'] # []
Other option is to use setdefault:
d.setdefault('turns', []) # []
d.setdefault('turns', 'foo') # []
UPDATE Given the full code you could either write
d = defaultdict(list, json.loads(str(self.data)))
d['turns'].append({'date': time_turn, 'data': data})
or
d = json.loads(str(self.data))
d.setdefault('turns', []).append({'date': time_turn, 'data': data})
Is there a oneliner in Python to do this?
Yes
d.setdefault('turns', [])
Demo:
>>> d = {}
>>> d.setdefault('turns', [])
[] # the inserted value is also returned
>>> d
{'turns': []}
If the key is found, setdefault behaves like get:
>>> d['turns'].append(1)
>>> d.setdefault('turns', 'irrelevant')
[1]
depending on if the get is standard, it likely has the option to specify a default return if the item is not found, so
d.get('turns', [])
will give you the value if it exists, or [] if it doesn't.
Well, you can "oneline" it using :
d['turns'] = [] if not d.get('turns')
Related
Here I have a list like this.
ls = ['Small:u', 'Small:o']
What I want is to create a dictionary of each list items like this.
dict1 = {'Small':'u'}
dict2 = {'Small':'o'}
How can I do it ? Is it possible?
>>> x = [dict([pair.split(":", 1)]) for pair in ['Small:u', 'Small:o']]
>>> x
[{'Small': 'u'}, {'Small': 'o'}]
Yes, it is possible, but one thing I'm not sure whether is possible (or a good idea at all) is to programmatically assign variable names to new dictionaries, so instead the easier way is to create a dictionary of dictionaries:
dic_of_dics = {}
for index, item in enumerate(ls):
i, j = item.split(':')
dic_of_dics[f'dict{index}'] = {i : j}
This is another way:
ls = ['Small:u', 'Small:o']
dict_list = []
for i in ls:
k, v = i.split(':')
dict_list.append({k: v})
print(dict_list)
print(dict_list[1].values())
Perhaps with minimal line:
ls = ['Small:u', 'Small:o']
dict_list = map(lambda x:dict([x.split(':')]), ls)
# for python3: print(list(dict_list))
# for Python2: print(dict_list)
Explanation: I am using map function to convert the list of string to list of lists. Then I am passing it through dict(to convert them to dictionary).
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 have a prototype dictionary that i want to use as a basis for appending to a list.
I want to change 1 or more values in the dictionary then capture it as an element of a list.
My question is this; is there any other recommended method for doing this short of using deepcopy().
I know this doesn't work properly:
l = []
d = {}
d['key'] = 4
l.append(d)
d['key'] = 5
l.append(d)
it gives:
l = [{'key': 5}, {'key': 5}]
it also didn't seem to work using a simply copy()
You are appending a reference to the same object to both lists, so when you change the value of "key", you change it in both lists. You need to make a copy of the dictionary before appending if you want a separate reference, using the dict.copy function:
l = []
d = {}
d['key'] = 4
l.append(d.copy())
d['key'] = 5
l.append(d.copy())
If you need a deep copy, you can use the copy library:
import copy
l = []
d = {}
d['key'] = 4
l.append(copy.deepcopy(d))
d['key'] = 5
l.append(copy.deepcopy(d))
copy should work.
l = []
d = {}
d['key'] = 4
l.append(d)
d = d.copy()
d['key'] = 5
l.append(d)
Result:
[{'key': 4}, {'key': 5}]
I have a following dictionary:
d = {'key':{'key2':[]}}
Is there any way to append to d['key']?
I want to get:
d = {'key':{'key2':[], 'key3':[]}}
d['key'] = ['key3'] apparently does not produce the desired outcome..
I know I can do
d = {'key': [{'key2': []}]}
and then append to d['key'] in a loop, but I am trying to avoid that..
You're looking for
d['key']['key3'] = []
Alternate solution.
d['key'].update({'key3':[]})
Since d["key"] is a dictionary, you can set keys in this dictionary as usual:
e = d["key"]
e["key3"] = []
or simply
d["key"]["key3"] = []
Why not trying:
d['key']['key3'] = []
That should work.
I need to populate dictionary from array. I've done in three lines and i'm trying to do it shortest as it can be. Is there way how to populate it in single line?
a = [['test',154],['test2',256]]
d = dict()
for b in a:
d[b[0]] = b[1]
Just dict :)
>>> a = [['test',154],['test2',256]]
>>> dict(a)
{'test': 154, 'test2': 256}
You just do dict(a) or dict([['test',154],['test2',256]]).
L = [['test',154],['test2',256]]
In Python 3.x:
d = {k:v for k,v in L}
In Python 2.x:
d = dict([(k,v) for k,v in L])