I have a list of the folowing form:
oldlist = [{'x': 1, 'y':2},{'x':2, 'y':2},{'x':1, 'y':3},{'x':1, 'y':2},{'x':3, 'y':4}]
to be converted into
final = [{'x':1,'y':[2,3,2],'count':3},{'x':2,'y':[2],'count':1},{'x':3,'y':[4],'count':1}]
I have tried
oldlist = [{'x': {'a':1,'b':2}, 'y':2},{'x':{'a':6,'b':7}, 'y':2},{'x':{'a':1,'b':2}, 'y':3},{'x':{'a':1,'b':2}, 'y':2},{'x':{'a':10,'b':11}, 'y':4}]
list1=[]
list2=[]
list3=[]
s = set([d['x'] for d in oldlist])
news=list(s)
for item in oldlist:
if item['x'] == news[0]:
list1.append(item['y'])
if item['x'] == news[1]:
list2.append(item['y'])
if item['x'] == news[2]:
list3.append(item['y'])
final=[]
dic1 = {'x':news[0],'y':list1,'count':len(list1)}
dic2 = {'x':news[1],'y':list2,'count':len(list2)}
dic3 = {'x':news[2],'y':list3,'count':len(list3)}
final.append(dic1)
final.append(dic2)
final.append(dic3)
print final
Is there a simpler way to do it? Plus here I knew that x can have only three values so I created three variables list1, list2 and list3. What if x can have several other values and I have to find out a similar list of dictionaries like final! It should also work for strings!
You can collect the dicts to defaultdict where key is x from original dicts and value is list of related y values. Then use list comprehension to generate the final result:
from collections import defaultdict
l = [{'x':1, 'y':2},{'x':2, 'y':2},{'x':1, 'y':3},{'x':1, 'y':2},{'x':3, 'y':4}]
res = defaultdict(list)
for d in l:
res[d['x']].append(d['y'])
final = [{'x': k, 'y': v, 'count': len(v)} for k, v in res.items()] # [{'y': [2, 3, 2], 'x': 1, 'count': 3}, {'y': [2], 'x': 2, 'count': 1}, {'y': [4], 'x': 3, 'count': 1}]
x_list = [item['x'] for item in list1]
set_value = set(x_list)
final_lst = []
for i in set_value:
d = {}
d['x'] = i
d['count'] = x_list.count(i)
d['y'] = []
for item in list1:
if item['x'] == d['x']:
d['y'].append(item['y'])
final_lst.append(d)
print ("Final List", final_lst)
Ok, I used a little trick here to do the job, it's not the most pythonic way but it still gets the answer you want.
The problem was indexing? So a changed s to t, where t is a list and changed the end of the code because you have to put the keys on your dictionaries as strings, so x become 'x' and so on.
See the whole code below:
lista = [{'x':1, 'y':2},{'x':2, 'y':2},{'x':1, 'y':3},{'x':1, 'y':2},{'x':3, 'y':4}]
list1=[]
list2=[]
list3=[]
for d in lista:
print(d)
s = set([d['x'] for d in lista])
t = []
for element in s: #turn t into a list which has the same ordering as s
t.append(element)
for item in lista:
if item['x'] == t[0]:
list1.append(item['y'])
if item['x'] == t[1]:
list2.append(item['y'])
if item['x'] == t[2]:
list3.append(item['y'])
final=[]
dic1 = {'x':t[0],'y':list1,'count':len(list1)}
dic2 = {'x':t[1],'y':list2,'count':len(list2)}
dic3 = {'x':t[2],'y':list3,'count':len(list3)}
final.append(dic1)
final.append(dic2)
final.append(dic3)
print(final)
Related
I wrote the following code and i cannot understand why my dictionary is being deleted alone with my list.
Really hope you could help me with it.. iam kind of stuck here.
This is my code :
course_dict = {'I': 3, 'love': 3, 'self.py!': 2}
save_dict = {}
def inverse_dict(Recived_dict):
global save_dict
list_counter = 0
new_dict = {}
my_list = []
current_value = list(Recived_dict.values())[0]
for key, value in Recived_dict.items():
if value == current_value:
my_list.append(key)
new_dict[value] = my_list
save_dict = new_dict
else:
if list_counter == 0:
del my_list[0:]
list_counter =1
my_list.append(key)
new_dict[value] = my_list
print(new_dict)
inverse_dict(course_dict)
Since you have values that are not unique, you need a way to aggregate the original keys that correspond to the original values. You can start with a dictionary with the new keys and blank lists for the values, and then append the new values:
course_dict = {'I': 3, 'love': 3, 'self.py!': 2}
def inverse_dict(Recived_dict):
new_dict = {v: [] for v in Recived_dict.values()}
for k, v in Recived_dict.items():
new_dict[v].append(k)
print(new_dict)
inverse_dict(course_dict)
{3: ['I', 'love'], 2: ['self.py!']}
Assuming you will want to be able to use this new dictionary, your function should probably return the inverted dictionary:
def inverse_dict(Recived_dict):
new_dict = {v: [] for v in Recived_dict.values()}
for k, v in Recived_dict.items():
new_dict[v].append(k)
return new_dict
course_dict = {'I': 3, 'love': 3, 'self.py!': 2}
save_dict = inverse_dict(course_dict)
print(save_dict)
{3: ['I', 'love'], 2: ['self.py!']}
defaultdict will make this much easier.
from collections import defaultdict
a = {3: 'foo', 5: 'foo', 4: 'bar'}
d = defaultdict(list)
for k, v in a.items():
d[v].append(k)
Result:
defaultdict(<class 'list'>, {'foo': [3, 5], 'bar': [4]})
So if I want to find the same key and add up the values in a list of dictionary.
[{'hello':10,'hi':2},{'hi':3}] will return 5 if I'm finding the key name'hi'
sum and a list comprehension can solve this pretty easily.
x = [{'hello': 10, 'hi': 2}, {'hi': 3}, {'nohihere': 8}]
all_hi = sum(d.get('hi', 0) for d in x)
print(all_hi)
5
You can try this:
dlist = [{'hello':10,'hi':2},{'hi':3}]
sum(map(lambda x: x.get('hi',0), dlist))
you just need to check if each object has key with 'hi'
list = [{'hello':10,'hi':2},{'hi':3},{'nothi':4}]
sum = 0
for i in list:
if 'hi' in i:
sum += i['hi']
print(sum)
This is another solution
my_dict = [{'hello':10,'hi':2},{'hi':3}]
common_keys = set.intersection(*map(set, my_dict))
summed_dict = {key: sum(d[key] for d in my_dict) for key in common_keys}
print(summed_dict)
o/p - {'hi': 5}
else you can use this
import functools as ft
my_dict = [{'hello':10,'hi':2},{'hi':3}]
print({k: sum(d[k] for d in my_dict) for k in ft.reduce(set.intersection, map(set, my_dict))})
o/p - {'hi': 5}
I have a general list with information:
lis = ["Hello", "Hello1", "Test"]
Then I have a dictionary with filepathes to .c files as values and keys are extensions of the lis values like:
dict1 = {"/****Hello****/":
["C://test/hello/one.c",
"C://test/hello/two.c"],
"/****Hello1****/":
["C://test/helloNext/one.c",
"C://test/helloNext/two.c"],
"/****Test****/":
["C://test/bye/one.c",
"C://test/bye/two.c"]}
The idea is to replace the keys of dict1 with the values of lis, if values of lis are in the key information.
for x in lis:
for y in dict1.copy():
if x in y:
dict1[x] = dict1.pop(y)
As far as good but now I found a big problem:
If I do it that way, some information of dict1 are overwritten because in this example, it searches for a key with "Hello" in it and overwrites dict1[0] but also overwrites dict1[1] to "Hello" instead of "Hello1" because it's the first information...
I don't get to a solution on my own.
I think I am just missing a little bit...
Thanks!
PS: It is not a solution to just cut out special characters from the keys, because it does not look the same for every file..
One way would be to sort the list based on the length of the elements and process it in the reverse order:
lis = ["Hello", "Hello1", "Test"]
dict1 = {"/****Hello****/": ["C://test/hello/one.c", "C://test/hello/two.c"],
"/****Hello1****/": ["C://test/helloNext/one.c", "C://test/helloNext/two.c"],
"/****Test****/": ["C://test/bye/one.c", "C://test/bye/two.c"]}
for x in sorted(lis, key=len, reverse=True):
for y in dict1:
if x in y and y not in lis:
dict1[x] = dict1.pop(y)
break
print(dict1)
# {'Hello1': ['C://test/helloNext/one.c', 'C://test/helloNext/two.c'], 'Hello': ['C://test/hello/one.c', 'C://test/hello/two.c'], 'Test': ['C://test/bye/one.c', 'C://test/bye/two.c']}
You can sort your first list by descending length and then create a copy of your original dictionary, moving each element from the first to the new dict.
In [1]:
llist = ["a", "aa", "ab", "c"]
dict1 = {"xax": 1, "xaax": 2, "xabx": 3, "xabcx": 4}
llist.sort(key=len, reverse=True)
dict2 = dict()
for key in dict1:
success = False
for replace_token in llist:
if replace_token in key:
dict2[replace_token] = dict1.get(key)
success = True
break
if not success:
dict2[key] = dict1.get(key)
print(dict2)
Out [1]:
{'a': 1, 'aa': 2, 'ab': 4}
The general problem is in my code, as well as in your example. It is overwriting all previous values. So I suppose those values shall be in a list:
In [1]:
from typing import List
llist = ["a", "aa", "ab", "c"]
dict1 = {"xax": 1, "xaax": 2, "xabx": 3, "xabcx": 4}
llist.sort(key=len, reverse=True)
dict2 = dict()
for key in dict1:
success = False
for replace_token in llist:
if replace_token in key:
current = dict2.get(replace_token, [])
new = dict1.get(key)
if isinstance(new, List):
current.extend(new)
else:
current.append(new)
dict2[replace_token] = current
success = True
break
if not success:
dict2[key] = dict1.get(key)
print(dict2)
Out [1]:
{'a': [1], 'aa': [2], 'ab': [3, 4]}
You can use re.findall:
import re
lis = ["Hello","Hello1","Test"]
dict1 = {"/****Hello****/": ["C://test/hello/one.c", "C://test/hello/two.c"], "/****Hello1****/": ["C://test/helloNext/one.c", "C://test/helloNext/two.c"], "/****Test****/": ["C://test/bye/one.c", "C://test/bye/two.c"]}
_lis = sorted(lis, key=len, reverse=True)
new_dict = {re.findall('|'.join(_lis), a)[0]:b for a, b in dict1.items()}
Output:
{'Hello': ['C://test/hello/one.c', 'C://test/hello/two.c'], 'Hello1': ['C://test/helloNext/one.c', 'C://test/helloNext/two.c'], 'Test': ['C://test/bye/one.c', 'C://test/bye/two.c']}
import re
lis = ["Hello","Hello1","Test"]
dict1 = {"/****Hello****/": ["C://test/hello/one.c", "C://test/hello/two.c"],
"/****Hello1****/": ["C://test/helloNext/one.c", "C://test/helloNext/two.c"],
"/****Test****/": ["C://test/bye/one.c", "C://test/bye/two.c"]}
dict2 = {}
for x in lis:
print('x:',x)
for y in dict1.copy():
y2 = (y.replace('*', ''))
y2 = (y2.replace('/', ''))
if x == y2:
print(x,y2)
dict2[x] = dict1[y]
print(dict2)
Alternative: no using dict2
if x == y2:
print(x,y2)
dict1[x] = dict1[y]
del dict1[y]
OUTPUT
{'Hello': ['C://test/hello/one.c', 'C://test/hello/two.c'], 'Hello1': ['C://test/helloNext/one.c', 'C://test/helloNext/two.c'], 'Test': ['C://test/bye/one.c', 'C://test/bye/two.c']}
So my input values are as follows:
temp_dict1 = {'A': [1,2,3,4], 'B':[5,5,5], 'C':[6,6,7,8]}
temp_dict2 = {}
val = [5]
The list val may contain more values, but for now, it only contains one. My desired outcome is:
>>>temp_dict2
{'B':[5]}
The final dictionary needs to only have the keys for the lists that contain the item in the list val, and only unique instances of that value in the list. I've tried iterating through the two objects as follows:
for i in temp_dict1:
for j in temp_dict1[i]:
for k in val:
if k in j:
temp_dict2.setdefault(i, []).append(k)
But that just returns an argument of type 'int' is not iterable error message. Any ideas?
Changed your dictionary to cover some more cases:
temp_dict1 = {'A': [1,2,3,4], 'B':[5,5,6], 'C':[6,6,7,8]}
temp_dict2 = {}
val = [5, 6]
for item in val:
for key, val in temp_dict1.items():
if item in val:
temp_dict2.setdefault(key, []).append(item)
print(temp_dict2)
# {'B': [5, 6], 'C': [6]}
Or, the same using list comprehension (looks a bit hard to understand, not recommended).
temp_dict2 = {}
[temp_dict2.setdefault(key, []).append(item) for item in val for key, val in temp_dict1.items() if item in val]
For comparison with #KeyurPotdar's solution, this can also be achieved via collections.defaultdict:
from collections import defaultdict
temp_dict1 = {'A': [1,2,3,4], 'B':[5,5,6], 'C':[6,6,7,8]}
temp_dict2 = defaultdict(list)
val = [5, 6]
for i in val:
for k, v in temp_dict1.items():
if i in v:
temp_dict2[k].append(i)
# defaultdict(list, {'B': [5, 6], 'C': [6]})
You can try this approach:
temp_dict1 = {'A': [1,2,3,4,5,6], 'B':[5,5,5], 'C':[6,6,7,8]}
val = [5,6]
def values(dict_,val_):
default_dict={}
for i in val_:
for k,m in dict_.items():
if i in m:
if k not in default_dict:
default_dict[k]=[i]
else:
default_dict[k].append(i)
return default_dict
print(values(temp_dict1,val))
output:
{'B': [5], 'C': [6], 'A': [5, 6]}
I have a list of the folowing form:
oldlist = [{'x': {'a':1,'b':2}, 'y':2},{'x':{'a':6,'b':7}, 'y':2},{'x':{'a':1,'b':2}, 'y':3},{'x':{'a':1,'b':2}, 'y':2},{'x':{'a':10,'b':11}, 'y':4}]
to be converted into
final = [{'x':{'a':1,'b':2},'y':[2,3,2],'count':3},{'x':{'a':6,'b':7},'y':[2],'count':1},{'x':{'a':10,'b':11},'y':[4],'count':1}]
I have tried
oldlist = [{'x': {'a':1,'b':2}, 'y':2},{'x':{'a':6,'b':7}, 'y':2},{'x':{'a':1,'b':2}, 'y':3},{'x':{'a':1,'b':2}, 'y':2},{'x':{'a':10,'b':11}, 'y':4}]
list1=[]
list2=[]
list3=[]
s = set([d['x'] for d in oldlist])
news=list(s)
for item in oldlist:
if item['x'] == news[0]:
list1.append(item['y'])
if item['x'] == news[1]:
list2.append(item['y'])
if item['x'] == news[2]:
list3.append(item['y'])
final=[]
dic1 = {'x':news[0],'y':list1,'count':len(list1)}
dic2 = {'x':news[1],'y':list2,'count':len(list2)}
dic3 = {'x':news[2],'y':list3,'count':len(list3)}
final.append(dic1)
final.append(dic2)
final.append(dic3)
print final
Getting
s = set([d['x'] for d in oldlist])
TypeError: unhashable type: 'dict'
Is there a simpler way to do it? Plus here I knew that x can have only three values so I created three variables list1, list2 and list3. What if x can have several other values and I have to find out a similar list of dictionaries like final! It should also work for strings!
EDIT:I tried this. But it all got messed up
s = list(frozenset(oldlist[0]['x'].items()))
print s
for item in oldlist:
s.append(frozenset(item['x'].items()))
The set function can only handle hashable objects, like a string, number, tuple e.t.c
Data types like List, dict are unhashable types, and hence the set function cannot handle them.
For some more clarity:
What do you mean by hashable in Python?
http://blog.lerner.co.il/is-it-hashable-fun-and-games-with-hashing-in-python/
A basic implementation of what you need:
for elem in oldlist:
found = False
for item in newlist:
if elem['x'] == item['x']:
y = item.get('y',[])
item['y'] = t.append(elem['y'])
found = True
break
if not found:
newlist.append({'x':elem['x'], 'y':[elem['y']]})
This will give you the expected result
You can use defaultdict where keys are frozenset objects created from value of x in the original dicts and values are list of relative y. Then you can construct the final result with list comprehension and turn frozensets back to dicts:
from collections import defaultdict
oldlist = [{'x': {'a':1,'b':2}, 'y':2},{'x':{'a':6,'b':7}, 'y':2},{'x':{'a':1,'b':2}, 'y':3},{'x':{'a':1,'b':2}, 'y':2},{'x':{'a':10,'b':11}, 'y':4}]
res = defaultdict(list)
for d in oldlist:
res[frozenset(d['x'].items())].append(d['y'])
final = [{'x': dict(k), 'y': v, 'count': len(v)} for k, v in res.items()] # [{'y': [2, 3, 2], 'x': {'a': 1, 'b': 2}, 'count': 3}, {'y': [4], 'x': {'a': 10, 'b': 11}, 'count': 1}, {'y': [2], 'x': {'a': 6, 'b': 7}, 'count': 1}]
Set function of python does not allow dictionaries and you can not force it, try another method instead. (Take a closer look of the comment on the 5th and 6th line)
Try this code:
oldlist = [{'x': {'a':1,'b':2}, 'y':2},{'x':{'a':6,'b':7}, 'y':2},{'x':{'a':1,'b':2}, 'y':3},{'x':{'a':1,'b':2}, 'y':2},{'x':{'a':10,'b':11}, 'y':4}]
list1=[]
list2=[]
list3=[]
s = [d['x'] for d in oldlist] # Placed the dictionaries in a list
s = result = [dict(tupleized) for tupleized in set(tuple(item.items()) for item in s)] # This is the manual way on removing duplicates dictionaries in a list instead of using set
news=list(s)
for item in oldlist:
if item['x'] == news[0]:
list1.append(item['y'])
if item['x'] == news[1]:
list2.append(item['y'])
if item['x'] == news[2]:
list3.append(item['y'])
final=[]
dic1 = {'x':news[0],'y':list1,'count':len(list1)}
dic2 = {'x':news[1],'y':list2,'count':len(list2)}
dic3 = {'x':news[2],'y':list3,'count':len(list3)}
final.append(dic1)
final.append(dic2)
final.append(dic3)
print final