add list value of a key in a dictionary python - python

I have a following dictionary:
centroid = {'A': [1.0, 1.0], 'B': [2.0, 1.0]}
Using the above dictionary I am creating two different dictionaries and appending them to a list:
for key in centroids:
clusters_list.append(dict(zip(key, centroids.get(key))))
However when I check my cluster_list I get the following data:
[{'A': 1.0}, {'B': 2.0}]
instead of
[{'A': [1.0, 1.0]}, {'B': [2.0, 1.0]}].
How can i fix this?

You can use a list comprehension:
For Python 2:
cluster_list = [{k: v} for k, v in centroid.iteritems()]
# [{'A': [1.0, 1.0]}, {'B': [2.0, 1.0]}]
For Python 3:
cluster_list = [{k: v} for k, v in centroid.items()]

You can also use starmap from itertools module.
In [1]: from itertools import starmap
In [2]: list(starmap(lambda k,v: {k:v}, centroid.items()))
Out[2]: [{'B': [2.0, 1.0]}, {'A': [1.0, 1.0]}]
And of course, it doesn't guarantee the order in the resulting list.

Related

How to group a dictionary by the first character of their key-values and sort them in ascending order?

I'd like to group the dictionary by the first character of their key-value, find the minimum and maximum value and sort them in ascending order of the maximum value found.
dict = {'1,1': [1.0, 2.0], '3,1': [5.0, 8.0], '2,2': [3.0, 9.0], '2,1': [3.0, 11.0]}
The dictionary after grouping, finding the max and min value, and sort in ascending order of their maximum values should be:
dict = {'1': [1.0, 2.0], '3': [5.0, 8.0], '2': [3.0, 11.0]}
First you can keep concatenating the lists grouped by k[0], and then take minimum and maximum of the lists:
dct = {'1,1': [1.0, 2.0], '3,1': [5.0, 8.0], '2,2': [3.0, 9.0], '2,1': [3.0, 11.0]}
output = {}
for k, v in dct.items():
output[k[0]] = output.get(k[0], []) + v
output = {k: [min(v), max(v)] for k, v in output.items()}
print(output) # {'1': [1.0, 2.0], '3': [5.0, 8.0], '2': [3.0, 11.0]}
Alternatively, if you are willing to use defaultdict:
from collections import defaultdict # this at the beginning of the script
output = defaultdict(list)
for k, v in dct.items():
output[k[0]] += v
output = {k: [min(v), max(v)] for k, v in output.items()}
this works but maybe someone has a more elegant answer:
dictionnary = {'1,1': [1.0, 2.0], '3,1': [5.0, 8.0], '2,2': [3.0, 9.0], '2,1': [3.0, 11.0]}
a = [i[0] for i in dictionnary.keys()]
b = dict.fromkeys(a)
for i in b:
b[i] = []
for j in dictionnary:
if j[0] == i:
if b[i]:
if dictionnary[j][0]<b[i][0]:
b[i][0] = dictionnary[j][0]
if dictionnary[j][1]>b[i][1]:
b[i][1] = dictionnary[j][1]
else:
b[i] = dictionnary[j]
b
Output:
{'1': [1.0, 2.0], '3': [5.0, 8.0], '2': [3.0, 11.0]}
Also, you shouldn't overwrite the builtin python dict

Add nested dictionaries on matching keys

I have a nested dictionary, such as:
{'A1': {'T1': [1, 3.0, 3, 4.0], 'T2': [2, 2.0]}, 'A2': {'T1': [1, 0.0, 3, 5.0], 'T2': [2, 3.0]}}
What I want to do is sum each sub dictionary, to obtain this:
A1 A2 A1 A2
T1+T1 T2+T2 (ignore the first entry of the list)
[3.0, 5.0, 9.0] <<<< output
1 2 3
res 3.0 + 0.0 = 3.0 and 2.0 + 3.0 = 5.0 and 5.0 + 4.0 = 9.0
How can I do this? I've tried a for, but I've created a big mess
One way is to use collections.Counter in a list comprehension, and sum the resulting Counter objects:
from collections import Counter
d = {'A1': {'T1': 3.0, 'T2': 2.0}, 'A2': {'T1': 0.0, 'T2': 3.0}}
l = (Counter(i) for i in d.values())
sum(l, Counter())
# Counter({'T1': 3.0, 'T2': 5.0})
For sum to work here, I've defined an empty Counter() as the start argument, so sum expects other Counter objects.
To get only the values, you can do:
sum(l, Counter()).values()
# dict_values([3.0, 5.0])
you could use a list comprehension with zip:
d = {'A1': {'T1': 3.0, 'T2': 2.0}, 'A2': {'T1': 0.0, 'T2': 3.0}}
[sum(e) for e in zip(*(e.values() for e in d.values()))]
output:
[3.0, 5.0]
this will work if your python version is >= 3.6
also, you can use 2 for loops:
r = {}
for dv in d.values():
for k, v in dv.items():
r.setdefault(k, []).append(v)
result = [sum(v) for v in r.values()]
print(result)
output:
[3.0, 5.0]
after your edit
you could use:
from itertools import zip_longest
sum_t1, sum_t2 = list(list(map(sum, zip(*t))) for t in zip(*[e.values() for e in d.values()]))
[i for t in zip_longest(sum_t1[1:], sum_t2[1:]) for i in t if i is not None]
output:
[3.0, 5.0, 6, 9.0]

How to count unique key elements in a tuple in a defaultdict (python)?

I have the following dictionary, keys being tuples:
defaultdict(<class 'float'>, {('abc', 'xyz'): 1.0, ('abc', 'def'):
3.0, ('abc', 'pqr'): 1.0, ('pqr', 'xyz'): 1.0, ('pqr', 'def'): 1.0})
How do I count up the first key element and second key element,
so that I can get:
defaultdict(<class 'float'>, {'abc': 3.0, 'pqr': 3.0})
and
defaultdict(<class 'float'>, {'xyz': 2.0, 'def': 2.0, 'pqr': 1.0})
I am ignoring the values in the original dictionary and just counting up unique keys (first and second separately).
I want to do something like the following, but I get an error "'tuple' object has no attribute 'items'":
first_key_list =[j[0][0] for i in dictionary for j in i.items()]
new_dict = collections.defaultdict(float)
for i in first_key_list:
new_dict[i] += 1
You're on the right track with your approach. But I'd recommend using a Counter object if you want to count things.
from collections import Counter
c1 = Counter(k[0] for k in d.keys())
c2 = Counter(k[1] for k in d.keys())
Truthfully, d.keys() is redundant here, since iteration is over the keys by default.
c1
Counter({'abc': 3, 'pqr': 2})
c2
Counter({'def': 2, 'pqr': 1, 'xyz': 2})
for i in dictionary for j in i.items() doesn't work because outer loop yields the dictionary keys (the tuples), and items don't apply to tuples.
Anyway, it seems that you're ignoring the values of your dictionaries. Just use collections.Counter on the first part of the key:
d = {('abc', 'xyz'): 1.0, ('abc', 'def'):
3.0, ('abc', 'pqr'): 1.0, ('pqr', 'xyz'): 1.0, ('pqr', 'def'): 1.0}
import collections
d1 = collections.Counter(k[0] for k in d)
print(d1)
result:
Counter({'abc': 3, 'pqr': 2})
if you want floats, I suggest that you convert to float after having counted to avoid floating point inaccuracy:
{k:float(v) for k,v in d1.items()}
or in one line:
d1 = {k:float(v) for k,v in collections.Counter(k[0] for k in d).items()}
to keep keys as tuples:
d1 = {(k,):float(v) for k,v in collections.Counter(k[0] for k in d).items()}
for the second part, just use k[1] instead.

Sum dictionary items based on rank

I can sum items in a list of dicts per key like so:
import functools
dict(
functools.reduce(
lambda x, y:x.update(y) or x,
dict1,
collections.Counter())
)
But given that
dict1 = [{'ledecky': 1, 'king': 2, 'vollmer': 3},
{'ledecky': 1, 'vollmer': 2, 'king': 3},
{'schmitt': 1, 'ledecky': 2, 'vollmer': 3}]
how could I sum their values according to medal value, given that:
medal_value = {1: 10.0, 2: 5.0, 3: 3.0}
Such that the final dict would yield:
{'ledecky': 25.0, 'king': 8.0, 'vollmer': 11.0, 'schmitt': 10.0}
The get() dictionary function works really well in this example, we either give the newly created dictionary a default value of 0 or add it's current value with the weighted value using our value (the value of dict1) as the search key.
def calculate_points(results, medal_value):
d = {}
for item in results:
for key, value in item.iteritems():
d[key] = d.get(key, 0) + medal_value[value]
return d
Sample output:
dict1 = [{'ledecky': 1, 'king': 2, 'vollmer': 3},
{'ledecky': 1, 'vollmer': 2, 'king': 3},
{'schmitt': 1, 'ledecky': 2, 'vollmer': 3}]
medal_value = {1 : 10.0, 2 : 5.0, 3 : 3.0}
print calculate_points(dict1, medal_value)
>>> {'ledecky': 25.0, 'king': 8.0, 'schmitt': 10.0, 'vollmer': 11.0}
Just define a lookup function to transform the original dict to a medal values dict:
def lookup(d):
return dict((k, medal_value[v]) for k, v in d.items())
And apply this function to your update part of the expression:
dict(
functools.reduce(
lambda x, y: x.update(lookup(y)) or x,
dict1,
collections.Counter())
)

Finding the mean of nodes in an undirected graph

I have written a program which gives me the following outputs for five nodes which is the shortest path from each node to different nodes :
G1= {'D': 3.0, 'E': 4.0, 'B': 1.0, 'C': 5.0, 'A': 0}
G1={'D': 2.0, 'E': 3.0, 'B': 0, 'C': 4.0, 'A': 1.0}
G1={'D': 2.0, 'E': 3.0, 'B': 4.0, 'C': 0, 'A': 5.0}
G1={'D': 0, 'E': 1.0, 'B': 2.0, 'C': 2.0, 'A': 3.0}
G1={'D': 1.0, 'E': 0, 'B': 3.0, 'C': 3.0, 'A': 4.0}
I am trying to find the mean of all of the nodes from the above output. I tried the following code :
for s in G:
G1=ShortestPaths(G,s)#this gives the output i mentioned above
mean= sum([G1[s] for s in G1])/(len(G1)-1)# this is where i am not getting result
return float(mean)
But it is giving mean of only the last line.I need sum of all the values in the dictionary(sum of 25 values) and divide by 20(since there is a zero in every line of my output.I should not consider that). Can anyone help me with this with a simple code?? I am not suppose to .items and other built-in functions.
Calculate the mean at the end, after the loop:
total = 0.0
count = 0.0
for s in G:
G1=ShortestPaths(G,s)
total += sum([G1[s] for s in G1])
count += (len(G1)-1)
return float(total / count) if count else None

Categories