Merging 2 dictionaries in Python but keeping the values - python

This might be a possible duplicate.
I have 2 dictionaries in this format:
dict1={'id1':'11', 'id2':'12', 'key11':'value11', 'key12':'value12'}
dict2={'id1':'n/a', 'id2':'12', 'key21':'value21', 'key22':'value22'}
Notice that the only common key between the 2 dictionaries is id2. So I want my final dict to be something like this:
dict3={'id1':'11', 'id2':'12', 'key11':'value11', 'key12':'value12', 'key21':'value21', 'key22':'value22'}
Also, notice that on the 2nd dictionary. id1 is missing, but on the final output, dict3 is using the value from dict1 because from id2 we know it's the same dictionary.
And finally, if dict2 has no matching keys with dict1, like this:
dict1={'id1':'11', 'id2':'12', 'key11':'value11', 'key12':'value12'}
dict2={'id1':'n/a', 'id2':'somevalue', 'key21':'value21', 'key22':'value22'}
Can then dict3 be dict2 with the dict1 keys but the values set to 'n/a'?? Like this:
dict3={'id1':'n/a', 'id2':'somevalue', 'key21':'value21', 'key22':'value22', 'id2':'n/a', 'key11':'n/a', 'key12':'n/a'}
I'm traversing 2 lists of dictionaries to do this. So my code so far is this:
for d1 in dlist1:
for d2 in dlist2:
if d1['id1']==d2['id1']:
if d1['id2'] == 'n/a':
d1['id2'] = d2['id2']
d1['key21'] = d2['key21']
# adding the new key-value pairs to dictionary 1, one-by-one and so on ...
In short, I'm either adding new fields to one of the nodes in dlist1 or adding an entirely new node to dlist1.
My question is: Is there a quicker pythonic way to do this? Because my implementation is giving me KeyError's

Related

Element-wise addition of lists nested in two dictionaries (Python)

I have two dictionaries, and the value for every key is a list of two elements, something like this:
dict1 = {1234: [40.26, 4.87], 13564 [30.24, 41.74], 523545 [810.13, 237.94]}
dict2 = {1231: [43.26, 8.87], 13564 [904.71, 51.81], 52234 [811.13, 327.35]}
I would like to get something like this:
dict3 = {1234: [40.26, 4.87], 1231: [43.26, 8.87], 13564 [934.95, 93.55], 523545 [810.13, 237.94], 52234 [811.13, 327.35]}
So far I have tried many things, but no luck.
Does anybody know the answer for this element-wise addition?
Copy one of the dictionaries to the result. Then loop through the other dictionary, creating or adding to the corresponding key in the result.
from copy import deepcopy
dict3 = deepcopy(dict1)
for key, value in dict2.items():
if key in dict3:
dict3[key] = [value[0] + dict3[key][0], value[1] + dict3[key][1]]
else:
dict3[key] = value.copy()

Change list according to dictionary items

Hello I have a list that looks like:
>>>ids
'70723295',
'75198124',
'140',
'199200',
'583561',
'71496270',
'69838760',
'70545907',
...]
I also have a dictionary that gives those numbers a 'name'. Now I want to create a new list that contains only the names, in the order like the numbers before.. so replace the numbers in the right order with the right names from the dictionary.
I tried:
with open('/home/anja/Schreibtisch/Master/ABA/alltogether/filelist.txt') as f:
ids = [line.strip() for line in f.read().split('\n')]
rev_subs = { v:k for v,k in dictionary.items()}
new_list=[rev_subs.get(item,item) for item in ids]
#dict looks like:
'16411': 'Itgax',
'241041': 'Gm4956',
'22419': 'Wnt5b',
'20174': 'Ruvbl2',
'71833': 'Dcaf7',
...}
But new_list is still the same as ids.
What am I doing wrong?
Maybe the dictionary keys are not in the format you think? Maybe the dictionary contains integers, meanwhile the ids are strings. I would investigate on that, it seems a mismatch of types more than an empty (or non-matching) dictionary.
Your dictionary keys are bs4.element.NavigableString objects rather than strings, so you cannot use strings as keys to look up its values.
You can fix this by converting the keys to strings when you build rev_subs:
rev_subs = {str(k): v for k, v in dictionary.items()}

Python Comparing Values of Numpy Array Between 2 Dictionaries Value

I have 2 dictionary and an input
letter = 'd'
dict_1 = {"label_1": array(['a','b']), "label_2": array(['c','d']), ...}
dict_2 = {"label_1": array(['x','y']), "label_2": array(['z','o']), ...}
letter_translated = some_function(letter)
output desired: 'o'
What I have in mind right now is to get the index number from the array of the key "label_2" in dict_1 then searching for the same index in dict_2. I am open to other way of doing it. If you are unclear about the question, feel free to drop a comment.
Note: the arrays are numpy arrays
I propose to iterate through the first dictionary, while keeping a trace of how to get to the current element (key and i) so that we can look in the second dict in the same place:
from numpy import array
dict_1 = {"label_1": array(['a','b']), "label_2": array(['c','d'])}
dict_2 = {"label_1": array(['x','y']), "label_2": array(['z','o'])}
def look_for_corresponding(letter, d1, d2):
for key, array_of_letters in d1.items():
for position, d1_letter in enumerate(array_of_letters):
if d1_letter == letter:
return d2[key][position]
return None # Line not necessary, but added for clarity
output = look_for_corresponding('d', dict_1, dict_2)
print(output)
# o
Of course, this code will fail if dict_1 and dict_2 do not have exactly the same structure, or if the arrays are more than 1D. If those cases apply to you, please edit your question to indicate it.
Also, I am not sure what should be done if the letter is not to be found within dict_1. This code will return None, but it could also raise an exception.
What do you mean with 'index'? The number?
dictionaries don't have the concept of counted indices of their entries. You can only access data through the key (here "label_2"), or by iterating (for key in dict_1 ...).
The order is not guaranteed and can change. The order or your declaration is not kept.
If you wish to have "label_2" in both, then you need to access
key = "label_2"
item_from_1 = dict_1[key]
item_from_2 = dict_2[key]
If you need to iterate dict_1, then on each item find the appropriate item in the second, then this also needs to go over the key:
for (key,value1) in dict_1.iteritems():
value2 = dict_2[key]
.....
Note that the order the items come up in the loop may vary. Even from one run of the program to the next.

Pulling up "dict" value of nested JSON by one level

I'm looking at converting some Chef run_lists to tags, and would like to automate the process.
So far what I've done is created a variable that runs:
# write to file instead of directly to variable for archival purposes
os.system("knife search '*:*' -a expanded_run_list -F json > /tmp/hostname_runlist.json")
data = json.load(open('/tmp/hostname_runlist.json'))
From there, I have a dict within a dict with list values similar to this:
{u'abc.com': {u'expanded_run_list': None}}
{u'foo.com': {u'expanded_run_list': u'base::default'}}
{u'123.com': {u'expanded_run_list': [u'utils::default', u'base::default']}}
...
I would like to convert that to a more simpler dictionary by removing the 'expanded_run_list' portion, as it it's not required at this point, so in the end it looks like this:
abc.com:None
foo.com:'base::default'
123.com:['utils::default', 'base::default']
I would like to keep the values as a list, or a single value depending on what is returned. When I run a 'for statement' to iterate, I can pull the hostnames from i.keys, but would need to remove the expanded_run_list key from i.values, as well as pair the key values up appropriately.
From there, I should have an easier time to iterate through the new dictionary when running an os.system Chef command to create the new tags. It's been a few years since I've written in python, so am a bit rusty. Any descriptive help would be much appreciated.
Considering that you are having your list of dict objects as:
my_list = [
{u'abc.com': {u'expanded_run_list': None}},
{u'foo.com': {u'expanded_run_list': u'base::default'}},
{u'123.com': {u'expanded_run_list': [u'utils::default', u'base::default']}}
]
Then, in order to achieve your desired result, you may use a combination of list comprehension and dict comprehension as:
For getting the list of nested dictionary
[{k: v.get('expanded_run_list') for k, v in l.items()} for l in my_list]
which will return you the list of dict objects in your desired form as:
[
{u'abc.com': None},
{u'foo.com': u'base::default'},
{u'123.com': [u'utils::default', u'base::default']}
]
Above solution assumes that you only want the value of key 'expanded_run_list' to be picked up from each of your nested dictionary. In case it doesn't exists, dict.get will return None which will be set as value in your resultant dict.
For pulling up your nested dictionary to form single dictionary
{k: v.get('expanded_run_list') for l in my_list for k, v in l.items()}
which will return:
{
'foo.com': 'base::default',
'123.com': ['utils::default', 'base::default'],
'abc.com': None
}

Creating a "dictionary of sets"

I need to efficiently store data in something that would resemble a "dictionary of sets" e.g. have a dictionary with multiple (unique) values matching each unique key. The source of my data would be a (not very well) structured XML.
My idea is:
I will look through a number of elements and find keys. If the key does not exist, add it to dictionary, if it already exists, just add a new value in the corresponding key.
And the result would be something like:
{
'key1': {'1484', '1487', 1488', ...}
'key2': {'1485', '1486', '1489', ...}
'key3': {'1490', '1491', '1492', ...}
...
}
I need to add new keys on the go.
I need to push unique values into each set.
I need to be able to iterate through the whole dictionary.
I am not sure if this is even feasible, but if anybody could push me in the right direction, I would be more than thankful.
I'm not going to benchmark this but in my experience native dicts are faster
store = {}
for key, value in yoursource:
try:
store[key].add(value)
except KeyError:
store[key] = {value}
from collections import defaultdict
mydict = defaultdict(set)
mydict["key1"] |= {'1484', '1487', '1488'}
Iteration is just like the normal dict.
Using dict.setdefault() to create the key if it doesn't exist, and initialising it with an empty set:
store = {}
for key, value in yoursource:
store.setdefault(key, set()).add(value)

Categories