Given the following data structure:
out = {
'foo': { 'public':{}, 'private':{}, 'other':{} },
'bar': { 'public':{}, 'private':{}, 'other':{} }
}
I am attempting to slice out parts of the sub-structure to create a new dict. My use for this is to respond to requests with all data except that marked private.
To do the opposite is trivial:
response = {x,y['private'] for x,y in out.iteritems()}
Which constructs a dict for each foo and bar containing only the data marked private. But is there some functionality in the standard library (itertools perhaps) that would produce the following:
out = {
'foo': { 'public':{}, 'other':{} },
'bar': { 'public':{}, 'other':{} }
}
I have tried the following:
{x:(y['public'], y['other']) for x,y in out.iteritems()}
Although I would prefer to not use a tuple, and not explicitly name each sub-structure, as this is not reusable or scalable.
def remove(name, obj):
return {x:y for x,y in obj.iteritems() if x is not name}
{x:remove('private',y) for x,y in out.iteritems()}
This seems to work, but is there a better way? Any ideas?
You can break this down into parts; you want a new dictionary which has some parts removed. So create a function which can return a dictionary without the elements in question and call this is part of an iterator.
You're using dictionary comprehensions so something like this would work:
def remove_items(d, *items):
"""
Return dictionary copy with some items removed.
"""
return { a: b for a, b in d.iteritems() if a not in items }
print { x: remove_items(y, 'private') for x, y in out.iteritems() }
Would that be what you mean?
respose = {x:{'public': y['public'], 'other': y['other']} for x,y in out.iteritems()}
Try this:
response = {}
for x,y in out.iteritems():
response[x] = dict(y)
del response[x]['private']
If you don't mind destroying the original dictionary then just iterate over it del'ing the 'private' elements, otherwise you need to copy the second level dicts and then del the unwanted items.
Related
I have the following piece of code:
payload = [
{
'car': {
'vin': message.car_reference.vin,
'brand': message.car_reference.model_manufacturer,
'model': message.car_reference.model_description,
'color': message.car_reference.color,
},
}
]
The only field on message.car_reference that is guaranteed to not be None is vin.
I still want the other keys (brand, model, color) to be in the dict only if they have a value.
The payload gets send to an external API that gives me an error if e.g. color = None.
How do I make it so that keys and values are only added, if their value is not None?
What came to my mind until now was mutlitple if-statements, but that looks awful and I don't think it's the right way.
This code recursively looks inside the data structure
def recur_remover(collection):
if isinstance(collection, list):
# This allows you to pass in the whole list immediately
for item in collection:
recur_remover(item)
elif isinstance(collection, dict):
# When you hit a dictionary, this checks if there are nested dictionaries
to_delete = []
for key, val in collection.items():
if val is None:
to_delete.append(key)
else:
recur_remover(collection[key])
for k in to_delete:
# deletes all unwanted keys at once instead of mutating the dict each time
del collection[k]
else:
return
If I understand your problem correctly, you may do this
your_car_collection = [{'car': {k: v for k, v in car['car'].items() if v}} for car in your_car_collection]
This question already has answers here:
Access nested dictionary items via a list of keys?
(20 answers)
Closed 5 years ago.
So I have a list which acts as a 'map' of sorts, and a dict which is pulled from a JSON file.
For this example, lets say they look like this:
L = ['One', 'Two', 'Three']
D = {
"One": {
"Two": {
"Three": {
"Four": "String"
}
}
}
}
I need a function for my game.
I will be passing it two things: L and a Object.
Note that L just leads to "Three" so thats what I want to replace. Though, I could be replacing "Four" or any other element at an unknown debth.
What I'm replacing could be a string, list, or dict, and I could be replacing it with any other object, including None, or a bool.
The structure of D needs to remain intact, besides the value being replaced.
This function will take a list of strings as a path and an object to replace the located value with, operating on a global variable nested_dicts. If you want to adhere to a functional paradigm, you might want to rewrite it accordingly.
def replace (path, replacement):
pointer = nested_dicts
try:
for key in path[:-1]:
pointer = pointer[key]
except KeyError:
return False
pointer[path[-1]] = replacement
return True
Something like this works (path is L, o is the replacement):
L = ['One', 'Two', 'Three']
D = {
"One": {
"Two": {
"Three": {
"Four": "String"
}
}
}
}
def replace(path, o):
cur = D
for k in path[:-1]:
cur = cur[k]
cur[path[-1]] = o
replace(L, {'msg': 'good'})
print(D)
I have a requirement in which I need create dictionary objects with duplicate keys embedded into a list object, something like this:
[{ "key": "ABC" },{ "key": "EFG" } ]
I decided to have a top level list initialized to empty like outer_list=[] and a placeholder dictionary object like dict_obj= {}. Next I keep adding elements to my list using the following steps:
assign { "key": "ABC" } to dict_obj using dict_obj["key"]="ABC"
Add this object to the list using outer_list.append(dict_obj)
Flush/pop the key/items in dictionary object using dict_obj.clear()
Repeat steps 1 to 3 based on the number of key/item combinations in my data
Issue: the outer_list object maintains a reference to the original dict_obj and if the dict_obj is flushed or a new key/item is added it changes accordingly. So finally, I end up with this [{ "key": "EFG" },{ "key": "EFG" } ] instead of [{ "key": "ABC" },{ "key": "EFG" } ]
Please guide me with some workarounds if possible.
I think there are two ways to avoid the duplicate references.
The first is to append a copy of the dictionary, instead of a reference to it. dict instances have a copy method, so this is easy. Just change your current append call to:
outer_list.append(dict_obj.copy())`
The other option is to not always use the same dict_obj object, but rather create a separate dictionary object for each entry. In this version, you'd replace your call to dict_obj.clear() with:
dict_obj = {}
For the second approach, you might choose to reorder things rather than doing a straight one-line replacement. You could move the setup code to the start of the loop and get rid of the reset logic at the end of the loop.
That is, change code that looks like this:
outer_list = []
dict_obj = {}
for foo in whatever:
# add stuff to dict_obj
outer_list.append(dict_obj)
dict_obj.clear()
To:
outer_list = []
for foo in whatever:
dict_obj = {}
# add stuff to dict_obj
outer_list.append(dict_obj)
If the logic for creating the inner dictionaries is simple enough to compute, you might even turn the whole thing into a list comprehension:
outer_list = [{"key": value, "key2": value2} for value, value2 in some_sequence]
The following should be self-explanatory:
# object reuse
d = {}
l = []
d['key'] = 'ABC'
l.append(d)
d.clear()
print(l) # [{}] : cleared!
d['key'] = 'EFG'
l.append(d)
print(l) # [{'key': 'EFG'}, {'key': 'EFG'}]
# explicit creation of new objects
d = {}
l = []
d['key'] = 'ABC'
l.append(d)
print(l)
d = {}
d['key'] = 'EFG'
l.append(d)
print(l)
{255:
{255:
{1:
{2:{}
}
}
}
},
{255:
{255:
{2:
{3:{}
}
}
}
}
My dictionary is highly complex (even more entries than shown above)
Now I want to merge two dictionaries
output should be :
{255:
{255:
{1:
{2:{}
}
},
{2:
{3:{}
}
}
}
also the maximum nesting possible is till level 5.
Not sure if I understood, but how about this:
def merge(a, b):
for x in b:
if x in a:
merge(a[x], b[x])
else:
a[x] = b[x]
return a
Here's a simple variation on georg's answer that doesn't clobber either of the argument values (it returns a copies of the data in new dictionaries, rather than reusing the existing ones):
import copy
def merge(a, b, copy_a=True):
if copy_a:
a = copy.deepcopy(a)
for x in b:
if x in a:
merge(a[x], b[x], copy_a=False)
else:
a[x] = copy.deepcopy(b[x])
return a
The extra argument is used to make the code copy the first dictionary on the first call, but not on any of the recursive calls (since they've already been copied by then). It's an implementation detail, and you would always use the default when calling it from other code.
Suppose I have this:
list = [ { 'p1':'v1' } ,{ 'p2':'v2' } ,{ 'p3':'v3' } ]
I need to find p2 and get its value.
You can try the following ... That will return all the values equivilant to the givenKey in all dictionaries.
ans = [d[key] for d in list if d.has_key(key)]
If this is what your actual code looks like (each key is unique), you should just use one dictionary:
things = { 'p1':'v1', 'p2':'v2', 'p3':'v3' }
do_something(things['p2'])
You can convert a list of dictionaries to one dictionary by merging them with update (but this will overwrite duplicate keys):
dict = {}
for item in list:
dict.update(item)
do_something(dict['p2'])
If that's not possible, you'll need to just loop through them:
for item in list:
if 'p2' in item:
do_something(item['p2'])
If you expect multiple results, you can also build up a list:
p2s = []
for item in list:
if 'p2' in item:
p2s.append(item['p2'])
Also, I wouldn't recommend actually naming any variables dict or list, since that will cause problems with the built-in dict() and list() functions.
These shouldn't be stored in a list to begin with, they should be stored in a dictionary. Since they're stored in a list, though, you can either search them as they are:
lst = [ { 'p1':'v1' } ,{ 'p2':'v2' } ,{ 'p3':'v3' } ]
p2 = next(d["p2"] for d in lst if "p2" in d)
Or turn them into a dictionary:
dct = {}
any(dct.update(d) for d in lst)
p2 = dct["p2"]
You can also use this one-liner:
filter(lambda x: 'p2' in x, list)[0]['p2']
if you have more than one 'p2', this will pick out the first; if you have none, it will raise IndexError.
for d in list:
if d.has_key("p2"):
return d['p2']
If it's a oneoff lookup, you can do something like this
>>> [i['p2'] for i in my_list if 'p2' in i]
['v2']
If you need to look up multiple keys, you should consider converting the list to something that can do key lookups in constant time (such as a dict)
>>> my_list = [ { 'p1':'v1' } ,{ 'p2':'v2' } ,{ 'p3':'v3' } ]
>>> my_dict = dict(i.popitem() for i in my_list)
>>> my_dict['p2']
'v2'
Start by flattening the list of dictionaries out to a dictionary, then you can index it by key and get the value:
{k:v for x in list for k,v in x.iteritems()}['p2']