Create a dictionary with specific pairs from other dictionaries - python

This list:
data=[[{'t1':'text1.txt','date1':'class1'}],[{'t2':'text2.txt','date2':'class2'}]]
data
gives
[[{'t1': 'text1.txt', 'date1': 'class1'}],
[{'t2': 'text2.txt', 'date2': 'class2'}]]
and I want to turn it into this:
EDIT brackets added
[[{'text1.txt': 'class1'}], [{'text2.txt': 'class2'}]]
which means:
to create a list where each sublist inside, will be comprised of a dictionary where the key would be the value of the first dictionary in the first sublist and the value would be the value of the second dictionary of the first sublist and so on for the following sublists.
My attempt was this:
se=[]
for i in data:
for j in i:
jk=j.values()
se.append(jk)
se

Iterate through each dictionary in nested list and create a tuple from values() method for each dictionary like this tuple(dict.values()). After converting to tuple you can use dict() to create dictionary from the tuple like this dict([tuple(dict.values())])
Note: If your dictionary has exactly two keys then only it will work.
res = [[dict([tuple(d.values())]) for d in lst]for lst in data]
print(res)
Output:
[[{'text1.txt': 'class1'}], [{'text2.txt': 'class2'}]]

Your code does most of the job. You can add another line to get the desired results:
In [108]: se
Out[108]: [dict_values(['text1.txt', 'class1']), dict_values(['text2.txt', 'class2'])]
In [109]: [[{list(x)[0]:list(x)[1]} for x in se]]
Out[109]: [[{'text1.txt': 'class1'}, {'text2.txt': 'class2'}]]

Try this:
data=[[{'t1':'text1.txt','date1':'class1'}],[{'t2':'text2.txt','date2':'class2'}]]
all_vals = [];
for i in data:
for j in i:
for key in j:
all_vals.append(j[key])
new_list = [];
for i in range(0,len(all_vals)-1):
if (i % 2) == 0:
new_dict = {};
new_dict = {all_vals[i]:all_vals[i+1]}
new_list.append(new_dict)
else:
continue
print(new_list)
Output:
[{'text1.txt': 'class1'}, {'text2.txt': 'class2'}]
This code works regardless of the length of your list.

The following function should convert the inputs to the outputs you requested.
def convert_to_list_of_list_of_dictionaries(input_dictionaries):
ret_dictionaries = []
for inp in input_dictionaries:
k, v = inp[0].values()
ret_dictionaries.append({k, v})
return ret_dictionaries
However, there are a few things going on with the input/outputs that are little concerning and make the data harder to work with.
On the input side, the data is being wrapped in an extra list that in this context, does not provide any function, and forces you to index the first element of the inner list to access the dict k, v = inp[0].values(). On the output side, we're doing the same thing, which makes it harder to iterate over the outputs. It would look something like:
# psuedocode
for kv in reformatted_outputs:
unwrapped_dict = kv[0]
key, value = next(iter(unwrapped_dict.items()))
# process key and value
instead, if you had an output format like ``{'text1.txt': 'class1', 'text2.txt': 'class2'}`, you could process data like:
key, value in reformatted_outputs.items():
# process key and value
If you have the ability to modify the inputs and outputs of what you're working on, this could save you some trouble, and anyone you're working with some head scratches.
If you wanted to modify the output format, your function could look something like:
def convert_to_single_dictionary(input_dictionaries):
ret = {}
for inp in input_dictionaries:
print(inp)
# it looks like the input data is being wrapped in an extra list
k, v = inp[0].values()
ret[k] = v
return ret
Hope this is helpful and thanks for asking the question!

Related

iteratively appending N items to list gives last item N times instead

I am accessing a list of dictionary items list_of_dict = [{'ka':'1a', 'kb':'1b', 'kc':'1c'},{'ka':'2a'},{'ka':'3a', 'kb':'3b', 'kc':'3c'}], and trying to conditionally append each entry to another list article_list using a function add_entries.
My desired output
article_list = [{x:1a, y:1b, z:1c}, {x:2a}, {x:3a, y:3b, z:3c}]
My code:
def add_entries(list_of_dict):
keys = ['x','y','z']
#defining a temporary dictionary here
my_dict = dict.fromkeys(keys,0)
entry_keys = ['ka','kb','kc']
my_list = []
for item in list_of_dict:
# conditionally append the entries into the temporary dictionary maintaining desired key names
my_dict.update({a: item[b] for a,b in zip(keys, entry_keys) if b in item})
my_list.append(my_dict)
return my_list
if __name__ == "__main__":
list_of_dict = [{'ka':'1a', 'kb':'1b', 'kc':'1c'},{'ka':'2a'},{'ka':'3a', 'kb':'3b', 'kc':'3c'}]
article_list = []
returned_list = add_entries(list_of_dict)
article_list.extend(returned_list)
My output
article_list = [{x:3a, y:3b, z:3c}, {x:3a, y:3b, z:3c}, {x:3a, y:3b, z:3c}]
Whats wrong
my_list.append(my_dict) appends a reference to the my_dict object to my_list. Therefore, at the end of the for loop in your example, my_list is a list of references to the exact same dictionary in memory.
You can see this for yourself using the function id. id, at least in CPython, basically gives you the memory address of an object. If you do
article_list.extend(returned_list)
print([id(d) for d in article_list])
You'll get a list of identical memory addresses. On my machine I get
[139920570625792, 139920570625792, 139920570625792]
The consequence is that updating the dictionary affects 'all of the dictionaries' in your list. (quotes because really there are not multiple dictionaries in your list, just many times the exact same one). So in the end, only the last update operation is visible to you.
A good discussion on references and objects in Python can be found in this answer https://stackoverflow.com/a/30340596/8791491
The fix
Moving the definition of my_dict inside the for loop, means that you get a new, separate dictionary for each element of my_list. Now, the update operation won't affect the other dictionaries in the list, and my_list is a list of references to several different dictionaries.
def add_entries(list_of_dict):
keys = ['x','y','z']
entry_keys = ['ka','kb','kc']
my_list = []
for item in list_of_dict:
#defining a new dictionary here
my_dict = dict.fromkeys(keys,0)
# conditionally append the entries into the temporary dictionary maintaining desired key names
my_dict.update({a: item[b] for a,b in zip(keys, entry_keys) if b in item})
my_list.append(my_dict)
return my_list
You can use this.
keys=['x','y','z']
res=[{k1:d[k]} for d in list_of_dict for k,k1 in zip(d,keys)]
output
[{'x': '1a'},
{'y': '1b'},
{'z': '1c'},
{'x': '2a'},
{'x': '3a'},
{'y': '3b'},
{'z': '3c'}]
Try this:
list_new_d=[]
for d in list_of_dict:
new_d={}
for k,v in d.items():
if k == 'ka':
new_d['x'] = v
if k == 'kb':
new_d['y'] = v
if k == 'kc':
new_d['z'] = v
list_new_d.append(new_d)

Find value in list of dicts and return id of dict

I'd like to try and find if a value is in a list of dicts, which can be done easily with:
if any(x['aKey'] == 'aValue' for x in my_list_of_dicts):
But this is only a boolean response, I'd like to not only check if the value is there, but to also access it afterwards, so something like:
for i, dictionary in enumerate(my_list_of_dicts):
if dictionary['aKey'] == 'aValue':
# Then do some stuff to that dictionary here
# my_list_of_dicts[i]['aNewKey'] = 'aNewValue'
Is there a better/more pythonic way of writing this out?
With next function, if expected to find only one target dict:
my_list_of_dicts = [{'aKey': 1}, {'aKey': 'aValue'}]
target_dict = next((d for d in my_list_of_dicts if d['aKey'] == 'aValue'), None)
if target_dict: target_dict['aKey'] = 'new_value'
print(my_list_of_dicts)
The output (input list with updated dictionary):
[{'aKey': 1}, {'aKey': 'new_value'}]
You can use a list comprehension. This will return a list of dictionaries that match your condition.
[x for x in my_list_of_dicts if x['aKey']=='aValue' ]

Deleting multiple items in a dict

I've searched around for the error it gives me, but I don't understand that quite well. They did something with for k, v in dbdata.items, but that didn't work for me neither, it gives me other errors.
Well, I want is to delete multiple items.
tskinspath = ['1', '2']
#
dbdata = {}
dbdata['test'] = {}
dbdata['test']['skins_t'] = {}
# Adds the items
dbdata['test']['skins_t']['1'] = 1
dbdata['test']['skins_t']['2'] = 0
dbdata['test']['skins_t']['3'] = 0
dbdata['test']['skins_t']['4'] = 0
# This doesn't work
for item in dbdata["test"]["skins_t"]:
if item not in tskinspath:
if dbdata["test"]["skins_t"][item] == 0:
del dbdata["test"]["skins_t"][item]
# exceptions.RunetimeError: dictonary changed size during iteration
Instead of iterating over the dictionary, iterate over dict.items():
for key, value in dbdata["test"]["skins_t"].items():
if key not in tskinspath:
if value == 0:
del dbdata["test"]["skins_t"][key]
On py3.x use list(dbdata["test"]["skins_t"].items()).
Alternative:
to_be_deleted = []
for key, value in dbdata["test"]["skins_t"].iteritems():
if key not in tskinspath:
if value == 0:
to_be_deleted.append(key)
for k in to_be_deleted:
del dbdata["test"]["skins_t"][k]
The error message says it: you shouldn't modify the dictionary that you are iterating over. Try
for item in set(dbdata['test']['skins_t']):
...
This way you are iterating over a set that contains all keys from dbdata['test']['skins_t'].
As the question details is way aside from the question, If you are looking for a solution that deletes multiple keys from a given dict use this snippet
[s.pop(k) for k in list(s.keys()) if k not in keep]
Additionally, you can create a new dict via comprehension.
new_dict = { k: old_dict[k] for k in keep }

return object from dictionary of nested lists when a condition (python)

I have a dictionary that looks like:
myD={'key_0':[[['descrp_0_0'],Obj_0_0],.....,[['descrp_0_N'],obj_0_N]]
,.....,
'key_N':[[['descrp_N_0'],Obj_N_0],.....,[['descrp_N_N'],obj_N_N]]}
All objs are ndarrays of the same shape and have a function f() that returns an x which is a float i.e.:
obj_0_0.f() --> x_0_0
I want to extract a dictionary with the descrp and obj and their respective key where obj.f() (i.e. x) is minimum for the values in each key (at the myD scope of N keys would give N items in shape of [descrp,obj]):
The result must look something like:
resD = {'key_0':[[descrp_0_min],obj_0_min],
.....,
'key_N':[[descrp_N_min],obj_0_min]}
Something like:
minXs = [min([item[-1].f() for item in v]) for k,v in myD.iteritems()]
minObjs = [item for k,v in myD.iteritems() for item in v if item[-1].get_potential_energy() == minXs[myD.keys().index(k)]]
resultList = zip(myD.keys(),minObjs)
resultDict = dict()
for i in resultList:
resultDict[i[0]]=i[1]
Although it works but is rather cumbersome and I think there must be an easier way to do this. Or maybe I should use numpy.ndarray for this purpose?
I appreciate your help and comments.
If I've understood the structure of your data correctly, I think you can solve this with a dictionary comprehension that calls the builtin min function and gives it a key function.
results = {key: min(values, key=lambda x:x[-1].f())
for key, values in myD.iteritems()}
Your code was really close already!

Defining a list of values for a dictionary key using an external file

I have a file with a list of paired entries (keys) that goes like this:
6416 2318
84665 88
90 2339
2624 5371
6118 6774
And I've got another file with the values to those keys:
266743 Q8IUM7
64343 H7BXU6
64343 Q9H6S1
64343 C9JB40
23301 Q8NDI1
23301 A8K930
As you can see the same key can have more than one value. What I'm trying to do is creating a dictionary by automatically creating the initial k, v pair, and then append more values for each entry that is already in the dictionary, like this:
Program finds "266743: 'Q8IUM7'", then "64343: 'H7BXU6'". And when it finds "64343: 'Q9H6S1'" it does this: "64343: ['H7BXU6', 'Q9H6S1']".
This is what I have so far:
# Create dictionary
data = {}
for line in inmap:
value = []
k, v = [x.strip() for x in line.split('\t')]
data[k] = value.append(v)
if k in data.viewkeys() == True and v in data.viewvalues() == False:
data[k] = value.append(v)
But the if statement seems to not be working. That or having the value = [] inside the for loop. Any thoughts?
This is not a good idea. You should be using a list from the start and expand that list as you go along, not change from "string" to "list of strings" when more than one value is found for the key.
For this, you can simply use
from collections import defaultdict
data = defaultdict(list)
for line in inmap:
k, v = (x.strip() for x in line.split('\t'))
data[k].append(v)
This works because a defaultdict of type list will automatically create a key together with an empty list as its value when you try to reference a key that doesn't yet exist. Otherwise, it behaves just like a normal dictionary.
Result:
>>> data
defaultdict(<type 'list'>, {'23301': ['Q8NDI1', 'A8K930'],
'64343': ['H7BXU6', 'Q9H6S1', 'C9JB40'], '266743': ['Q8IUM7']})

Categories