python create list of dictionaries without reference - python

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)

Related

How do I create a list inside python dictionary having key and key variable?

I have an empty dictionary. I add key and key variable to that dictionary. How do I create an empty list having key and key variable?
result = {}
result['key'] = 20
print(result)= {'key': 20}
result['key'] = []
result2 = {}
result['key'].append(result2)
Expected result : {'key':20 : [{'7219': '0.49954929481682875'}, {'1416': '0.48741579334133667'}
But it comes like,
{'key': [{'7219': '0.49954929481682875'}, {'1416': '0.48741579334133667'}]
Looks like you need.
result = {}
result['key'] = {20: []}
print(result) # --> {'key': {20: []}}
result2 = {}
result['key'][20].append(result2)
print(result)
As far as I understand your question, you do not necessarily want to save the value "20" with the key "key", but rather use "20" as the key. In order to achieve that, your code should look like the following (careful, this basically spells out every step):
# save an empty list using the key int(20)
# define the key and an empty dictionary
my_key = 20
result = {}
# use the key variable as key for the dictionary and create an empty list there
result[my_key] = []
# now add the other result dictionary to this list
result2 = {
#... some entries
}
result[my_key].append(result2)
# ... some more code
This finally results in a dictionary in this form:
{20 : [{'7219': '0.49954929481682875'}, {'1416': '0.48741579334133667'}]}
However, this is only my interpretation of your issue. If I got something wrong, just ping me up.

Updating a dictionary in a list in a dictionary - value change doesn't survive scope

I have a list of dictionaries, in a dictionary. I'm trying to update the value of one of the fields. Simplified example:
main = {
'list': [
{ 'value': 'hello', 'many many more': 'values' }
]
}
update_value = { 'value': 'test', 'many many more': 'values' }
for item in main['list']:
if True: # just to illustrate that I need to do some check here
item = update_value
print(item)
for item in main['list']:
print(item)
This produces the following output:
{'value': 'test'}
{'value': 'hello'}
When updating the dictionary in the list in this dictionary, the value change doesn't survive out of the scope. I have a vague understanding of why this is happening. I tried copying the dictionary, but that didn't work.
How can I make my changes to the main dictionary survive?
Using Moses Koledoye answer I've got this now, but it doesn't feel very "pretty". Is this really the "pythonic" way of doing this?
main = {
'list': [
{ 'value': 'hello', 'many many more': 'values' }
]
}
update_value = { 'value': 'test', 'many many more': 'values' }
for index, item in enumerate(main['list']):
if True: # just to illustrate that I need to do some check here
main['list'][index] = update_value
print(item)
for item in main['list']:
print(item)
Your approach only assigns the loop variable item to the new dict. Does not modify the existing dict.
You should assign the new value via dictionary subscription:
for item in main['list']:
item['value'] = update_value['value']
You can equally update the entire dict via list subscription:
main['list'][0] = update_value.copy()
Assigning a copy ensures the dict in the list is thereafter independent of update_value, so that modifications to update_value are not propagated to the dict in the list.
The approach with enumerate is quite ok. However, if the keys in both dicts are matching, you can do:
for dct in main['list']:
...
dct.update(update_value)
All the values are overwritten with the new ones.
This is happening because you are modifiying a copy of list instance but not original memory of list. So, you could try this one
main = {
'list': [
{ 'value': 'hello' }
]
}
update_value = { 'value': 'test' }
for i in range(len(main['list'])):
main['list'][i] = update_value
print(main['list'][i])
for item in main['list']:
print(item)

Appending parameters from a list in a for loop

I have a list with several data, ['a','b','c'...]
The goal here is to read all the items in the list and access to a json file to retrieve that information.
The json i have is as follows
{
"a": {
"b": {
"c": { .... }
}
} }
So, the final sentence to execute is
code.get(list[0]).get(list[1]).get(list[2]...get(list[n]
Is there any way i can do a for loop based on the length of the list to do this?
Something like, for any item in the list, append a ..get(list[i]) to my sentence
Thanks
Just iterate over the key list and go down into the code dict:
keys = ['a','b','c']
current_level = code # Top level
for key in keys:
current_level = current_level.get(key) # Descent next level
print current_level # Value of the 'c' dict

How do I find an item in an array of dictionaries?

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']

Python dict restructure

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.

Categories