Minimum Value Tuples when Values are stored in another dictionary - python

Suppose I have a list
[{0: [0, 1, 2, 3], 1: [4]}, {2: [5, 6, 7, 8], 3: [9]}, {4: [10, 11, 12]}]
and another dictionary
servicesdict = { 0 : {'cost' : 30},
1 : {'cost' : 50},
2 : {'cost' : 70},
3 : {'cost' : 20},
4 : {'cost' : 20},
5 : {'cost' : 10},
6 : {'cost' : 20},
7 : {'cost' : 50},
8 : {'cost' : 70},
9 : {'cost' : 20},
10 : {'cost' : 20},
11 : {'cost' : 20},
12 : {'cost' : 40},
}
I wrote
{k: [min(v, key = lambda x:servicesdict[x]['cost'])]for item in newlist for k, v in item.items()}to get the minimum cost of the list element in each subdictionary of the list
This produces the minimum list element not just the cost
{0: [0], 1: [4], 2: [5], 3: [9], 4: [10]}
How do I get the corresponding cost as well? That is, the output should be
{0: [0, 20], 1: [4, 20], 2: [5, 10], 3: [9, 20], 4: [10, 20]}

servicesdict = {
0: {'cost': 30},
1: {'cost': 50},
2: {'cost': 70},
3: {'cost': 20},
4: {'cost': 20},
5: {'cost': 10},
6: {'cost': 20},
7: {'cost': 50},
8: {'cost': 70},
9: {'cost': 20},
10: {'cost': 20},
11: {'cost': 20},
12: {'cost': 40},
}
newlist = [{0: [0, 1, 2, 3], 1: [4]}, {2: [5, 6, 7, 8], 3: [9]}, {4: [10, 11, 12]}]
mins = {
k: min([[servicesdict[x]['cost'], x] for x in sublist])
for dct in newlist
for k, sublist in dct.items()
}
print(mins)
# {0: [20, 3], 1: [20, 4], 2: [10, 5], 3: [20, 9], 4: [20, 10]}
Basically convert each sublist to a list of [cost, id] pairs and take the min of that. The default comparison for lists will compare the cost first. If you make [id, cost] pairs instead then you need to provide a key to sort by cost.

Perhaps the simplest approach here is to use the obtained list:
d = {k: [min(v, key = lambda x:servicesdict[x]['cost'])] for item in newlist
for k, v in item.items()}
And add the corresponding cost with the bellow dictionary comprehension:
{k: [*v, servicesdict[v[0]]['cost']] for k,v in d.items()}
# {0: [3, 20], 1: [4, 20], 2: [5, 10], 3: [9, 20], 4: [10, 20]}

You can apply min twice:
d = [{0: [0, 1, 2, 3], 1: [4]}, {2: [5, 6, 7, 8], 3: [9]}, {4: [10, 11, 12]}]
servicesdict = {0: {'cost': 30}, 1: {'cost': 50}, 2: {'cost': 70}, 3: {'cost': 20}, 4: {'cost': 20}, 5: {'cost': 10}, 6: {'cost': 20}, 7: {'cost': 50}, 8: {'cost': 70}, 9: {'cost': 20}, 10: {'cost': 20}, 11: {'cost': 20}, 12: {'cost': 40}}
result = {a:[min(b), min(servicesdict[i]['cost'] for i in b)] for c in d for a, b in c.items()}
Output:
{0: [0, 20], 1: [4, 20], 2: [5, 10], 3: [9, 20], 4: [10, 20]}
Edit: if you want the first element in each list to be the key of the minimum value in servicesdict, then min with key` can be applied:
result = {a:[min(b, key=lambda x:servicesdict[x]['cost']), min(servicesdict[i]['cost'] for i in b)] for c in d for a, b in c.items()}
Output:
{0: [3, 20], 1: [4, 20], 2: [5, 10], 3: [9, 20], 4: [10, 20]}

Related

python: use sorted() function for dict inside the dict

this is the dict I got now:
dict1 = {1: {7: [6], 1: [7]}, 2: {3: [1, 6], 2: [2, 7, 5]}}
And I would like to order subdictionary by keys:
dict2 = {1: {1: [7], 7: [6]}, 2: {2: [2, 7, 5], 3: [1, 6]}}
I tried some methods, but it didn't work...Like this one. Please help me.
print(sorted(dict1.items(), key=lambda x: x[1][1]))
As long as you use sufficiently high version of Python3 you can do:
dict1 = {1: {7: [6], 1: [7]}, 2: {3: [1, 6], 2: [2, 7, 5]}}
dict2 = {k: dict(sorted(v.items())) for k, v in dict1.items()}
print(dict2)
Prints:
{1: {1: [7], 7: [6]}, 2: {2: [2, 7, 5], 3: [1, 6]}}

nested Dictionary print differently after sorting by inner dictionary values in python

I was trying sorting nested dict by inner dict's value. The sorting went well. but when I check my result, I found out that the original dict was printed when I just use the variable (d2), but it gives me the correct result when I use print(d2)
d2 = {1: {1: 4, 2: 5, 3: 6},
2: {7: 13, 8: 14, 9: 15, 10: 16, 11: 17, 12: 18},
3: {1: 1, 2: 9, 3: 4}}
# sorting by inner dict value
for keys in d2.keys():
sorted_tuples = sorted(d2[keys].items(), key=operator.itemgetter(1), reverse=True)
d2[keys] = {k: v for k, v in sorted_tuples}
print(d2)
d2
{1: {3: 6, 2: 5, 1: 4}, 2: {12: 18, 11: 17, 10: 16, 9: 15, 8: 14, 7: 13}, 3: {2: 9, 3: 4, 1: 1}}
{1: {1: 4, 2: 5, 3: 6},
2: {7: 13, 8: 14, 9: 15, 10: 16, 11: 17, 12: 18},
3: {1: 1, 2: 9, 3: 4}}
why the output is different when I use d2 and print(d2)
friend! Did you use the pretty print module to print the results of d2? I was only able to replicate your behavior using the pretty print module. Pretty print alphabetically sorts a dictionary before printing it, which can be disabled.
I originally (and wrongly) suspected the different output between d2 and print(d2) was a result of dictionaries being unordered collections of data; I suspected dict.__str__ and dict.__repr__ differed just enough. I would recommend you use an OrderedDict over a standard dictionary if you wish to maintain its order--despite Python preserving dictionaries insertion order in Python 3.7.
Below is my code and conclusions.
After initialization, d2 and print(d2) printed the same values:
❯ python
Python 3.7.12 (default, Sep 10 2021, 17:29:55)
[Clang 12.0.5 (clang-1205.0.22.9)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> d2 = {1: {1: 4, 2: 5, 3: 6},
2: {7: 13, 8: 14, 9: 15, 10: 16, 11: 17, 12: 18},
3: {1: 1, 2: 9, 3: 4}}
>>> d2
{1: {1: 4, 2: 5, 3: 6}, 2: {7: 13, 8: 14, 9: 15, 10: 16, 11: 17, 12: 18}, 3: {1: 1, 2: 9, 3: 4}}
>>> print(d2)
{1: {1: 4, 2: 5, 3: 6}, 2: {7: 13, 8: 14, 9: 15, 10: 16, 11: 17, 12: 18}, 3: {1: 1, 2: 9, 3: 4}}
After sorting, d2 and print(d2) printed the same values.
>>> import operator
>>> for keys in d2.keys():
... sorted_tuples = sorted(d2[keys].items(), key=operator.itemgetter(1), reverse=True)
... d2[keys] = {k: v for k, v in sorted_tuples}
...
>>> print(d2)
{1: {3: 6, 2: 5, 1: 4}, 2: {12: 18, 11: 17, 10: 16, 9: 15, 8: 14, 7: 13}, 3: {2: 9, 3: 4, 1: 1}}
>>> d2
{1: {3: 6, 2: 5, 1: 4}, 2: {12: 18, 11: 17, 10: 16, 9: 15, 8: 14, 7: 13}, 3: {2: 9, 3: 4, 1: 1}}
However, while using the pretty print module, I was able to replicate your behavior.
>>> from pprint import pprint as pp
>>> pp(print(d2))
{1: {3: 6, 2: 5, 1: 4}, 2: {12: 18, 11: 17, 10: 16, 9: 15, 8: 14, 7: 13}, 3: {2: 9, 3: 4, 1: 1}}
>>> pp(d2)
{1: {1: 4, 2: 5, 3: 6},
2: {7: 13, 8: 14, 9: 15, 10: 16, 11: 17, 12: 18},
3: {1: 1, 2: 9, 3: 4}}
Once I disabled dictionary sorting in the pretty print module, I was able to obtain your desired output.
>>> pprint.sorted = lambda x, key=None: x
>>> pp(d2)
{1: {3: 6, 2: 5, 1: 4},
2: {12: 18, 11: 17, 10: 16, 9: 15, 8: 14, 7: 13},
3: {2: 9, 3: 4, 1: 1}}
>>> pp(print(d2))
{1: {3: 6, 2: 5, 1: 4}, 2: {12: 18, 11: 17, 10: 16, 9: 15, 8: 14, 7: 13}, 3: {2: 9, 3: 4, 1: 1}}

How to get and modify the value of nested dictionary?

I have this kind of dictionary in python:
x = {'test': {1: 2, 2: 4, 3: 5},
'this': {1: 2, 2: 3, 7: 6},
'is': {1: 2},
'something': {90: 2,92:3}}
I want to modify all of the value in the key by whatever value I want. Let's say 100, the methods I tried are below:
counter = 1
print(x)
for key,anotherKey in x.items():
while counter not in x[key]:
counter+=1
while counter in x[key]:
x[key][counter] = 100
counter+=1
counter =0
Which got the result below:
{'test': {1: 100, 2: 100, 3: 100},
'this': {1: 100, 2: 100, 7: 6},
'is': {1: 100},
'something': {90: 100,92: 3}}
I know why this is happening it's because the loop doesn't consider if the differences is more than 1 which in this case in 'this' : where the differences from 2 to 7 is more than 1. However I don't know how to solve this.
You can iterate via a nested for loop:
x = {'test': {1: 2, 2: 4, 3: 5},
'this': {1: 2, 2: 3, 7: 6},
'is': {1: 2},
'something': {90: 2,92:3}}
for a in x:
for b in x[a]:
x[a][b] = 100
print(x)
{'is': {1: 100},
'something': {90: 100, 92: 100},
'test': {1: 100, 2: 100, 3: 100},
'this': {1: 100, 2: 100, 7: 100}}
Or for a new dictionary you can use a dictionary comprehension:
res = {a: {b: 100 for b in x[a]} for a in x}
You can use dictionary comprehension in this way:
{a: {b:100 for b in d} for (a,d) in x.items()}

Hard copying dicts in a list

When I try the following list creation, I see that each element refers to a different object.
>>> a = [1] * 7
>>> a[0] = 2
>>> a
Out[17]: [2, 1, 1, 1, 1, 1, 1]
However, when I try the following list creation with dictionaries, I see that each element refers to the same object.
a = [{1:10, 2:20}] * 7
a[0][1] = 30
a
Out[20]:
[{1: 30, 2: 20},
{1: 30, 2: 20},
{1: 30, 2: 20},
{1: 30, 2: 20},
{1: 30, 2: 20},
{1: 30, 2: 20},
{1: 30, 2: 20}]
How can I create this second list as easy as possible, but with the elements copies instead of references?
>>> a = [{1:10, 2:20} for _ in range(7)]
>>> a[0][1] = 30
>>> a
[{1: 30, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}]
Actually when you create a list with multiplication python will creating a list with repeated items with same memory address :
>>> a=[1]*7
>>> id(a[0])
40968536
>>> id(a[1])
40968536
>>> a = [{1:10, 2:20}]*7
>>> id(a[0])
140379402804592
>>> id(a[1])
140379402804592
But when you want to change an immutable object like (numbers,tuple,string,...) python will change the reference not the object!
And when you change a mutable object python will change the object itself,so all the entries will change.
So as a more efficient way in python 2 you can use xrange (xrange return a generator instead a list) (in 3 range ) within a list comprehension to create your list :
>>> a = [{1:10, 2:20} for _ in xrange(7)]
>>> a
[{1: 10, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}]
>>> a[0][1]=0
>>> a
[{1: 0, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}, {1: 10, 2: 20}]
>>> id(a[0])
140379402734400
>>> id(a[1])
140379402809424

Converting list of lists of lists into dictionary of dictionaries (Python)

Suppose I have a list X = [[[2, 2]], [[2, 5], [3, 1]], [[3, 3], [4, 4], [1, 6]], [[1, 1], [4, 0]], [[]]]. I want to convert X into a dictionary of dictionaries like so.
G = {0: {2: 2},
1: {2: 5, 3: 1},
2: {3: 3, 4: 4, 1: 6},
3: {1: 1, 4: 0},
4: {}
}
So far I have
for i in range(0,len(X)):
for j in range(0, len(X[i])):
G[i] = {X[i][j][0]: X[i][j][1]}
which produces
{0: {2: 2}}
{0: {2: 2}, 1: {2: 5}}
{0: {2: 2}, 1: {3: 1}}
{0: {2: 2}, 1: {3: 1}, 2: {3: 3}}
{0: {2: 2}, 1: {3: 1}, 2: {4: 4}}
{0: {2: 2}, 1: {3: 1}, 2: {1: 6}}
{0: {2: 2}, 1: {3: 1}, 2: {1: 6}, 3: {1: 1}}
{0: {2: 2}, 1: {3: 1}, 2: {1: 6}, 3: {4: 0}}
Traceback (most recent call last):
G[i] = {X[i][j][0]: X[i][j][1]}
IndexError: list index out of range
First it only updates the dictionaries instead of appending new keys, second it fails me at my empty list.
Any suggestions?
If you're using Python 2.7 you can use a dictionary comprehension.
X = [[[2, 2]], [[2, 5], [3, 1]], [[3, 3], [4, 4], [1, 6]], [[1, 1], [4, 0]], [[]]]
d = {k: dict(v) if v[0] else {} for k, v in enumerate(X)}
someone had a nice answer but they deleted it where they also used a dictionary comprehension but handled the empty lists better (I think). It went like so
d = {k: dict(item for item in v if item) for k, v in enumerate(X)}
Your assignment to G should be:
G[i][X[i][j][0]] = X[i][j][1]
And you'll need to initialize each item of G before the inner loop:
G[i] = {}

Categories