Related
I have a list as follows:
[[a,a,b,a,b,b,b],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
The number of lists containing numerical values is the same as the elements in the first list (that contains letters "a" or "b"). The length of the lists containing numbers is unknown a priori.
Each letter corresponds to a list in this way:
a --> 5,5,4,5
a --> 5,1,5
b --> 2,5
a --> 4,5
b --> 5
b --> 3
b --> 5
And then, count each value by letters "a" or "b", while keeping the values, for example "a" has in total 6 "5", 2 "4", and 1 "1". "b" has in total 3 "5", 1 "2", and 1 "3".
Expected result:
"a" has in total 6 "5", 2 "4", and 1 "1".
"b" has in total 3 "5", 1 "2", and 1 "3".
One approach:
from collections import Counter, defaultdict
lst = [["a", "a", "b", "a", "b", "b", "b"], [5, 5, 4, 5], [5, 1, 5], [2, 5], [4, 5], [5], [3], [5]]
result = defaultdict(Counter)
head, *tail = lst
for key, values in zip(head, tail):
result[key] += Counter(values)
for key, counts in result.items():
print(key, counts)
Output
a Counter({5: 6, 4: 2, 1: 1})
b Counter({5: 3, 2: 1, 3: 1})
An alternative:
head, *tail = lst
counts = Counter((key, value) for key, values in zip(head, tail) for value in values)
result = defaultdict(dict)
for (key, value), count in counts.items():
result[key][value] = count
for key, value in result.items():
print(key, value)
Output
a {5: 6, 4: 2, 1: 1}
b {2: 1, 5: 3, 3: 1}
This would be my approach:
inputs = [['a','a','b','a','b','b','b'],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
counts = {}
for k, v in zip(inputs[0], inputs[1:]):
if k in counts.keys():
counts[k] += v
else:
counts[k] = v
My output for this:
{'a': [5, 5, 4, 5, 5, 1, 5, 4, 5], 'b': [2, 5, 5, 3, 5]}
Then you can use Counters, len(), etc. to get the exact output formatting you want.
See below ( Counter and defaultdict are the main "players")
from collections import Counter,defaultdict
results = defaultdict(Counter)
data = [['a','a','b','a','b','b','b'],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
for idx,x in enumerate(data[0],1):
results[x].update(data[idx])
for letter,counter in results.items():
print(f'{letter} -> {counter}')
output
a -> Counter({5: 6, 4: 2, 1: 1})
b -> Counter({5: 3, 2: 1, 3: 1})
It's a fun problem to solve.
from collections import Counter
data = [['a','a','b','a','b','b','b'],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
counts = { k:Counter() for k in list(set(data[0])) }
for i, k in enumerate(data[0], 1):
counts[k].update(data[i])
print(counts)
# {'a': Counter({5: 6, 4: 2, 1: 1}), 'b': Counter({5: 3, 2: 1, 3: 1})}
l = [["a","a","b","a","b","b","b"],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
d = {}
for i in l[0]:
if i not in d.keys():
d[i] = []
for i, item in zip(l[0],l[1:]):
d[i].append(item)
count_dict = {}
for i in d.keys():
count_dict[i] = {}
for j in d[i]:
elements = set(j)
for k in elements:
if str(k) not in count_dict[i].keys():
count_dict[i][str(k)] = j.count(k)
else:
count_dict[i][str(k)] += j.count(k)
for i,j in count_dict.items():
print('{} has {}'.format(i,j))
First off, you should really be doing your own homework
... I just love a good algo problem (adventOfCode, anyone?)
Steps:
don't forget " around strings in the list
create a dictionary to store counts within "a" and "b"
iterate over lists in indices 1-n
get the a/b bucket from: l[0][sublist_index - 1]
start a count for value, if not already counted: if v not in d[bucket].keys(): d[bucket][v] = 0
increment the counter for v, in the appropriate bucket: d[bucket][v] += 1
l = [["a","a","b","a","b","b","b"],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
d = {"a": {}, "b": {}}
for sublist_index in range(1, len(l)):
bucket = l[0][sublist_index - 1]
for v in l[sublist_index]:
if v not in d[bucket].keys():
d[bucket][v] = 0
d[bucket][v] += 1
print(d)
and the output:
{'a': {5: 6, 4: 2, 1: 1}, 'b': {2: 1, 5: 3, 3: 1}}
I have a dictionary where keys have the same values.
products = {
1: {1:1, 2:2, 3:3},
2: {1:1, 2:2, 3:3},
3: {1:1, 2:2, 3:3},
4: {1:2, 2:3, 3:4}
}
I'm looking for the fastest method to get their count without going into two for loops to compare them (since I'm working with 10000+ such key, value pairs)
{1:1, 2:2, 3:3}: 3
{1:2, 2:3, 3:4}: 1
The only solutions I could find was using collection.Counter but since it's a nested dictionary, it doesn't work. I could work with a list instead, but it doesn't really help.
You could turn the dictionaries into frozensets of their items. Those are hashable, so you can use Counter:
from collections import Counter
ctr = Counter(frozenset(d.items()) for d in products.values())
for k, v in ctr.items():
print(dict(k), v)
Output:
{1: 1, 3: 3, 2: 2} 3
{2: 3, 1: 2, 3: 4} 1
Benchmark results (Try it online!):
2.586 s U12_Forward
0.007 s dont_talk_just_code
Benchmark code:
from timeit import timeit
from collections import Counter
def U12_Forward(products):
x = [*products.values()]
return [(dct, x.count(dct)) for dct in products.values()]
def dont_talk_just_code(products):
ctr = Counter(frozenset(d.items()) for d in products.values())
return [(dict(k), v) for k, v in ctr.items()]
funcs = U12_Forward, dont_talk_just_code
products = {
1: {1:1, 2:2, 3:3},
2: {1:1, 2:2, 3:3},
3: {1:1, 2:2, 3:3},
4: {1:2, 2:3, 3:4}
}
products = {i+k: v for k, v in products.items() for i in range(0, 10000, 4)}
for _ in range(3):
for func in funcs:
t = timeit(lambda: func(products), number=1)
print('%.3f s ' % t, func.__name__)
print()
Something like?
>>> x = [*products.values()]
>>> {x.count(dct): dct for dct in products.values()}
{3: {1: 1, 2: 2, 3: 3}, 1: {1: 2, 2: 3, 3: 4}}
>>>
I have a list of tuples like this:
list = [(1,2),(1,3),(1,5),(0,8),(0,9),(0,1),(3,6),(3,7)]
I want to build a dictionary with sets of associate values like this:
result = {1:{2,3,5},0:{8,9,1},3:{6,7}}
I have this code:
return {x:y for (x,y) in list}
result = {1: 5, 0: 1, 3: 7}
But I have only the last value, I want all associate values in a set.
Thanks in advance
defaultdict could add value for a key without checking existence
from collections import defaultdict
mylist = [(1,2),(1,3),(1,5),(0,8),(0,9),(0,1),(3,6),(3,7)]
result = defaultdict(list)
for item in mylist:
result[item[0]].append(item[1])
SOLUTION:
This code snippet should solve your problem statement:
lst = [(1,2),(1,3),(1,5),(0,8),(0,9),(0,1),(3,6),(3,7)]
output_dict = dict()
[output_dict[t[0]].add(t[1]) if t[0] in list(output_dict.keys()) else output_dict.update({t[0]: {t[1]}}) for t in lst]
print(output_dict)
OUTPUT:
{1: {2, 3, 5}, 0: {8, 9, 1}, 3: {6, 7}}
This should help u:
lst = [(1,2),(1,3),(1,5),(0,8),(0,9),(0,1),(3,6),(3,7)]
result= {}
[result.setdefault(x, set()).add(y) for x,y in lst]
print(result)
Output:
{1: {2, 3, 5}, 0: {8, 9, 1}, 3: {6, 7}}
Incase if you want one liner:
In [10]: original_list = [(1,2),(1,3),(1,5),(0,8),(0,9),(0,1),(3,6),(3,7),(1,2)]
In [11]: {x: {r for(q, r) in original_list if q == x} for (x, y) in original_list}
Out[11]: {1: {2, 3, 5}, 0: {1, 8, 9}, 3: {6, 7}}
Here it is:
result = {}
for x, y in list:
if x not in result:
result[x] = []
result[x].append(y)
print(result)
I have a dictionary:
d = {1: 2,
2:3,
3: 4,
5:6,
6:7}
I want this output:
d= { 1: 4 , 2 :4 , 3:4 , 5:7 , 6:7}
basically 2 is parent of 1, 3 is parent of 2, 4 is parent of 3. I want to say that 1,2 and 3 is related to 4
For each key-value pair in the dict, you can use a while loop to keep checking if the current value is a valid key in the dict, and make the value of that key the new value, until the value is not a key, at which point you have found the leaf and you can assign that value to the current key:
for k, v in d.items():
while v in d:
v = d[v]
d[k] = v
so that given:
d = {1: 2,
2: 3,
3: 4,
5: 6,
6: 7}
d becomes:
{1: 4, 2: 4, 3: 4, 5: 7, 6: 7}
I have a list of dictionaries:
L = [{0:1,1:7,2:3,4:8},{0:3,2:6},{1:2,4:6}....{0:2,3:2}].
As you can see, the dictionaries have different length. What I need is to add missing keys:values to every dictionary to make them being with the same length:
L1 = [{0:1,1:7,2:3,4:8},{0:3,1:0,2:6,3:0,4:0},{0:0, 1:2,3:0,4:6}....{0:2,1:0,2:0,3:2,4:0}],
Means to add zeros for missing values. The maximum length isn't given in advance, so one may get it only iterating through the list.
I tried to make something with defaultdicts, like L1 = defaultdict(L) but it seems I don't understand properly how does it work.
You'll have to make two passes: 1 to get the union of all keys, and another to add the missing keys:
max_key = max(max(d) for d in L)
empty = dict.fromkeys(range(max_key + 1), 0)
L1 = [dict(empty, **d) for d in L]
This uses an 'empty' dictionary as a base to quickly produce all keys; a new copy of this dictionary plus an original dictionary produces the output you want.
Note that this assumes your keys are always sequential. If they are not, you can produce the union of all existing keys instead:
empty = dict.fromkeys(set().union(*L), 0)
L1 = [dict(empty, **d) for d in L]
Demo:
>>> L = [{0: 1, 1: 7, 2: 3, 4: 8}, {0: 3, 2: 6}, {1: 2, 4: 6}, {0: 2, 3: 2}]
>>> max_key = max(max(d) for d in L)
>>> empty = dict.fromkeys(range(max_key + 1), 0)
>>> [dict(empty, **d) for d in L]
[{0: 1, 1: 7, 2: 3, 3: 0, 4: 8}, {0: 3, 1: 0, 2: 6, 3: 0, 4: 0}, {0: 0, 1: 2, 2: 0, 3: 0, 4: 6}, {0: 2, 1: 0, 2: 0, 3: 2, 4: 0}]
or the set approach:
>>> empty = dict.fromkeys(set().union(*L), 0)
>>> [dict(empty, **d) for d in L]
[{0: 1, 1: 7, 2: 3, 3: 0, 4: 8}, {0: 3, 1: 0, 2: 6, 3: 0, 4: 0}, {0: 0, 1: 2, 2: 0, 3: 0, 4: 6}, {0: 2, 1: 0, 2: 0, 3: 2, 4: 0}]
The above approach to merge two dictionaries into a new one with dict(d1, **d2) always works in Python 2. In Python 3 additional constraints have been set on what kind of keys you can use this trick with; only string keys are allowed for the second dictionary. For this example, where you have numeric keys, but you can use dictionary unpacking instead:
{**empty, **d} # Python 3 dictionary unpacking
That'll work in Python 3.5 and newer.
a bit of caution: changes L
>>> allkeys = frozenset().union(*L)
>>> for i in L:
... for j in allkeys:
... if j not in i:
... i[j]=0
>>> L
[{0: 1, 1: 7, 2: 3, 3: 0, 4: 8}, {0: 3, 1: 0, 2: 6, 3: 0, 4: 0}, {0: 0, 1: 2, 2:
0, 3: 0, 4: 6}, {0: 2, 1: 0, 2: 0, 3: 2, 4: 0}]
Maybe not the most elegant solution, but should be working:
L = [{0:1,1:7,2:3,4:8},{0:3,2:6},{1:2,4:6},{0:2,3:2}]
alldicts = {}
for d in L:
alldicts.update(d)
allkeys = alldicts.keys()
for d in L:
for key in allkeys:
if key not in d:
d[key] = 0
print(L)
This is only a solution, but I think it's simple and straightforward. Note that it modifies the dictionaries in place, so if you want them to be copied, let me know and I'll revise accordingly.
keys_seen = []
for D in L: #loop through the list
for key in D.keys(): #loop through each dictionary's keys
if key not in keys_seen: #if we haven't seen this key before, then...
keys_seen.append(key) #add it to the list of keys seen
for D1 in L: #loop through the list again
for key in keys_seen: #loop through the list of keys that we've seen
if key not in D1: #if the dictionary is missing that key, then...
D1[key] = 0 #add it and set it to 0
This is quick and slim:
missing_keys = set(dict1.keys()) - set(dict2.keys())
for k in missing_keys:
dict1[k] = dict2[k]
Unless None is a valid value for a dictionary key you have herein is a great solution for you
L = [{0: 1, 1: 7, 2: 3, 4: 8}, {0: 3, 2: 6}, {1: 2, 4: 6}, {0: 2, 3: 2}]
for i0, d0 in enumerate(L[:-1]):
for d1 in L[i0:]:
_ = [d0.__setitem__(k,d1[k]) for k in d1 if d0.get(k,None) is None]
_ = [d1.__setitem__(k,d0[k]) for k in d0 if d1.get(k,None) is None]
print(L)
>>> [{0: 1, 1: 7, 2: 3, 3: 2, 4: 8}, {0: 3, 1: 2, 2: 6, 3: 2, 4: 6}, {0: 2, 1: 2, 2: 3, 3: 2, 4: 6}, {0: 2, 1: 7, 2: 3, 3: 2, 4: 8}]