Related
I have 2 dictionary :
First = {'A': 0.0, 'B': 0.0, 'C': 0.0, 'D': 0.0, 'E': 0.0, 'F': 0.0, 'G': 0.0, 'H': 0.0, 'I': 0.0, 'J': 0.0, 'K': 0.47, 'L': 0.0, 'M': 0.0, 'N': 0.0, 'O': 0.0, 'P': 0.0, 'Q': 0.0, 'R': 0.0, 'S': 0.41, 'T': 0.0}
and
Second = {'A': 0.0, 'B': 0.0, 'C': 0.0, 'D': 0.0, 'E': 0.0, 'F': 0.0, 'G': 0.0, 'H': 0.0, 'I': 0.18, 'J': 0.0, 'K': 1.0, 'L': 0.0, 'M': 0.0, 'N': 0.0, 'O': 0.0, 'P': 0.0, 'Q': 0.0, 'R': 0.0, 'S': 0.32, 'T': 0.0}
I woud like to drop certain values in second dict with conditions :
1 - if value in second dict is < to value un first dict, drop the (k,v) to the second dict
2 - if value in second dict == 0.0 then drop the (k,v) to the second dict
Fanaly, we have result :
Second = {'I': 0.18,'K': 1.0, 'S': 0.32}
Here is my code :
for key, value in dict(Second).items():
for key, value in dict(First).items():
if Second[value] == First[value] :
del Second[key]
elif First[value]> Second[value]:
del Second[key]
Second
But dont work :
KeyError: 0.0
Can someone help me !
You can't lookup a value as a key to a dictionary. Also, your 2nd loop is causing you to loop through the Second dictionary after you've already cleared all the elements that you want to clear.
You're looking for something more like:
for key, value in dict(Second).items():
if Second[key] == First[key] :
del Second[key]
elif First[key]> Second[key]:
del Second[key]
or even better
for key, value in Second.items():
if Second[key] <= First[key]:
del Second[key]
though your second condition, specifies it should be something more like:
for key, value in Second.items():
if Second[key] < First[key] or Second[key] == 0.0:
del Second[key]
Iterate through the first dict, since it won't be the one changing, and based on your conditions filter stuff out
for k,v in First.iteritems():
if Second[k] < v or Second[k] == 0.0:
del Second[k]
output:
{'I': 0.18, 'K': 1.0}
You are mistakenly using the item value rather than the key in an attempt to access the value. Also, you will run into problems if you attempt to mutate the dict while iterating over it. Instead, you could use dict comprehension.
For example:
d1 = {'A': 0.0, 'B': 0.0, 'C': 0.0, 'D': 0.0, 'E': 0.0, 'F': 0.0, 'G': 0.0, 'H': 0.0, 'I': 0.0, 'J': 0.0, 'K': 0.47, 'L': 0.0, 'M': 0.0, 'N': 0.0, 'O': 0.0, 'P': 0.0, 'Q': 0.0, 'R': 0.0, 'S': 0.41, 'T': 0.0}
d2 = {'A': 0.0, 'B': 0.0, 'C': 0.0, 'D': 0.0, 'E': 0.0, 'F': 0.0, 'G': 0.0, 'H': 0.0, 'I': 0.18, 'J': 0.0, 'K': 1.0, 'L': 0.0, 'M': 0.0, 'N': 0.0, 'O': 0.0, 'P': 0.0, 'Q': 0.0, 'R': 0.0, 'S': 0.32, 'T': 0.0}
d2 = {k: v for k, v in d2.items() if v != 0 and v != d1[k]}
print(d2)
# {'I': 0.18, 'K': 1.0, 'S': 0.32}
Let's say I have the following list of dict
t = [{'a': 1.0, 'b': 2.0},
{'a': 3.0, 'b': 4.0},
{'a': 5.0, 'b': 6.0},
{'a': 7.0, 'b': 9.0},
{'a': 9.0, 'b': 0.0}]
Is there an efficient way to extract all the values contained in the dictionaries with a dictionary key value of a?
So far I have come up with the following solution
x = []
for j in t:
x.append(j['a'])
However, I don't like to loop over items, and was looking at a nicer way to achieve this goal.
You can use list comprehension:
t = [{'a': 1.0, 'b': 2.0},
{'a': 3.0, 'b': 4.0},
{'a': 5.0, 'b': 6.0},
{'a': 7.0, 'b': 9.0},
{'a': 9.0, 'b': 0.0}]
new_list = [i["a"] for i in t]
Output:
[1.0, 3.0, 5.0, 7.0, 9.0]
Since this solution uses a for-loop, you can use map instead:
x = list(map(lambda x: x["a"], t))
Output:
[1.0, 3.0, 5.0, 7.0, 9.0]
Performance-wise, you prefer to use list-comprehension solution rather the map one.
>>> timeit('new_list = [i["a"] for i in t]', setup='from __main__ import t', number=10000000)
4.318223718035199
>>> timeit('x = list(map(lambda x: x["a"], t))', setup='from __main__ import t', number=10000000)
16.243124993163093
def temp(p):
return p['a']
>>> timeit('x = list(map(temp, t))', setup='from __main__ import t, temp', number=10000000)
16.048683850689343
There is a slightly difference when using a lambda or a regular function; however, the comprehension execution takes 1/4 of the time.
You can use itemgetter:
from operator import itemgetter
t = [{'a': 1.0, 'b': 2.0},
{'a': 3.0, 'b': 4.0},
{'a': 5.0, 'b': 6.0},
{'a': 7.0, 'b': 9.0},
{'a': 9.0, 'b': 0.0}]
print map(itemgetter('a'), t)
result:
[1.0, 3.0, 5.0, 7.0, 9.0]
Use a list comprehension as suggested in Ajax1234'a answer, or even a generator expression if that would benefit your use case:
t = [{'a': 1.0, 'b': 2.0}, {'a': 3.0, 'b': 4.0}, {'a': 5.0, 'b': 6.0}, {'a': 7.0, 'b': 9.0}, {'a': 9.0, 'b': 0.0}]
x = (item["a"] for item in t)
print(x)
Output:
<generator object <genexpr> at 0x7f0027def550>
The generator has the advantage of not executing or consuming memory until a value is needed. Use next() to take the next item from the generator, or iterate over it with a for loop.
>>> next(x)
1.0
>>> next(x)
3.0
>>> for n in x:
... print(n)
5.0
7.0
9.0
An alternative, albeit a expensive one, is to use pandas:
import pandas as pd
x = pd.DataFrame(t)['a'].tolist()
print(x)
Output:
[1.0, 3.0, 5.0, 7.0, 9.0]
I am currently trying to model a network flow problem by applying a max-flow-min-cut algorithm to a directed graph. I managed to create the graph and solve for the maximum flow (and flows) by using
nx.maximum_flow(DG, s="S", t="T")
what follows is:
(11.0,
{'A1': {'A4': 1.0, 'A5': 0, 'T': 3.0},
'A2': {'A1': 4.0, 'A8': 2.0, 'T': 1.0},
'A3': {'A7': 3.0},
'A4': {'A3': 0, 'A8': 0, 'T': 1.0},
'A5': {'A3': 2.0, 'A8': 1.0},
'A6': {'A2': 7.0},
'A7': {'T': 3.0},
'A8': {'T': 3.0},
'S': {'A3': 1.0, 'A5': 3.0, 'A6': 7.0},
'T': {}})
which is a two value tuple (11, and the rest in one value). Now I want to create an array that has includes the flows for, say, A1 -> A4, A5 -> A8 and A6 -> A2.
However, I am failing to create any sort of list from this, since I am quite new to Python.
Ideally, I'd end up with something like this:
y = np.array([1.0, 1.0, 7.0]).reshape(3,1)
[[ 1.]
[ 1.]
[ 7.]]
I don't understand what is a problem.
import numpy as np
data = (
11.0,
{
'A1': {'A4': 1.0, 'A5': 0, 'T': 3.0},
'A2': {'A1': 4.0, 'A8': 2.0, 'T': 1.0},
'A3': {'A7': 3.0},
'A4': {'A3': 0, 'A8': 0, 'T': 1.0},
'A5': {'A3': 2.0, 'A8': 1.0},
'A6': {'A2': 7.0},
'A7': {'T': 3.0},
'A8': {'T': 3.0},
'S': {'A3': 1.0, 'A5': 3.0, 'A6': 7.0},
'T': {}
}
)
lst = [ data[1]['A1']['A4'], data[1]['A5']['A8'], data[1]['A6']['A2'] ]
y = np.array( lst ).reshape(3,1)
print(y)
Result:
[[ 1.]
[ 1.]
[ 7.]]
I've implemented Yen's K-shortest path algorithm based on the pseudocode on Wikipedia and a few open-source codes on GitHub (https://gist.github.com/ALenfant/5491853 and https://github.com/Pent00/YenKSP). The only thing I did differently was instead of removing (i, i+1) edges completely, I changed the length of the edge to infinity (which is equivalent to removing the edges in essense I guess?)
I tested my code with a 10-node graph where all nodes are connected to each other. I expected the maximum number of loop-less routes I could generate is above 100 thousands but it turns out that my code could only find up to the 9th shortest route. Is this a limitation of Yen's?
Following is my code and the 10-node sample data.
def yen(nodes, distances, start, end, max_k):
# Dictionary "solspace" stores actual k-shortest paths, the first of which comes from Dijkstra's algorithm.
solspace = {}
potentialsolspace = []
selected = []
# Adding the Dijkstra's shortest path into solspace dictionary
solspace[0] = (dijkstra(nodes, distances, start, end))[0]
# max_k is the specified number of shortest paths you want to find
max_k = max_k
# Looping from k = 1 to k = max_K and the 0 to (size of previous entry of solspace)-1
# Reference: http://en.wikipedia.org/wiki/Yen's_algorithm
for k in range(1, max_k):
#distances = copy.deepcopy(actual_distances)
for i in range(0, (len(solspace[k - 1]) - 1)):
spur_node = solspace[k - 1][i]
spur_node_plus_one = solspace[k - 1][i + 1]
root_path = solspace[k - 1][0:i + 1]
for shortPath in solspace:
path_root_path = (solspace[shortPath])[0:i + 1]
#print(path_root_path)
if root_path == path_root_path and (len(solspace[shortPath]) - 1 > i):
# make each overlapping edges of root path and path_root_path infinity, hence impossible to select
distances[spur_node][spur_node_plus_one] = float('inf')
distances[spur_node_plus_one][spur_node] = float('inf')
# Call Dijkstra function to compute spur path (the shortest path between spur node
# and end ignoring the i,i+1 edge
spur_path_a = dijkstra(nodes, distances, spur_node, end)
spur_path = spur_path_a[0]
# Restore actual dist to distances nested dictionary
# Total path is just the combination of root path & spur path
total_path_tempo = root_path + spur_path
total_path = []
# This removes duplicates nodes but note that this is O(n^2) computing time, not efficient
# Ref: Stack Overflow questions:480214
[total_path.append(item) for item in total_path_tempo if item not in total_path]
print(total_path)
# build up potentialsolspace by adding in total path which are yet found in solspace or Potential
# hence, the use of nested if
if total_path not in solspace.values():
if [total_path, cost_path(total_path, distances)] not in potentialsolspace[:]:
potentialsolspace.append([total_path, cost_path(total_path, distances)])
distances = copy.deepcopy(actual_distances)
# This handles the case of there being no spur paths, or no spur paths left.
# This could happen if the spur paths have already been exhausted (added to A),
# or there are no spur paths at all such as when both the source and sink vertices lie along a "dead end".
if len(potentialsolspace) is 0:
break
wcg = min(potentialsolspace, key=lambda x: x[1])
# remove selected potential shortest path from the potential solspace
potentialsolspace.remove(wcg)
# Attach minimum of potentialSolSpace into solspace dictionary
solspace[k] = wcg[0]
return solspace
Following is the 10-node example arranged in Python nested distionary format. Primary keys are origins while secondary keys are neighbors of primary keys. Values equal the distance between primary key and secondary key.
{'A': {'C': 4.0, 'B': 10.0, 'E': 10.0, 'D': 10.0, 'G': 1.0, 'F': 2.0, 'I': 3.0, 'H': 3.0, 'J': 10.0}, 'C': {'A': 4.0, 'B': 5.0, 'E': 9.0, 'D': 6.0, 'G': 9.0, 'F': 10.0, 'I': 5.0, 'H': 10.0, 'J': 5.0}, 'B': {'A': 2.0, 'C': 10.0, 'E': 8.0, 'D': 1.0, 'G': 8.0, 'F': 4.0, 'I': 2.0, 'H': 2.0, 'J': 6.0}, 'E': {'A': 9.0, 'C': 5.0, 'B': 10.0, 'D': 4.0, 'G': 9.0, 'F': 9.0, 'I': 3.0, 'H': 3.0, 'J': 7.0}, 'D': {'A': 4.0, 'C': 6.0, 'B': 5.0, 'E': 7.0, 'G': 1.0, 'F': 1.0, 'I': 2.0, 'H': 9.0, 'J': 3.0},
'G': {'A': 2.0, 'C': 10.0, 'B': 3.0, 'E': 1.0, 'D': 10.0, 'F': 5.0, 'I': 5.0, 'H': 6.0, 'J': 1.0}, 'F': {'A': 2.0, 'C': 3.0, 'B': 6.0, 'E': 7.0, 'D': 8.0, 'G': 10.0, 'I': 1.0, 'H': 8.0, 'J': 2.0}, 'I': {'A': 1.0, 'C': 1.0, 'B': 2.0, 'E': 1.0, 'D': 6.0, 'G': 7.0, 'F': 1.0, 'H': 6.0, 'J': 2.0},
'H': {'A': 3.0, 'C': 4.0, 'B': 5.0, 'E': 1.0, 'D': 2.0, 'G': 6.0, 'F': 4.0, 'I': 1.0, 'J': 4.0},
'J': {'A': 5.0, 'C': 6.0, 'B': 1.0, 'E': 8.0, 'D': 7.0, 'G': 9.0, 'F': 8.0, 'I': 10.0, 'H': 1.0}}
I think the problem is in this part:
for shortPath in solspace:
path_root_path = (solspace[shortPath])[0:i + 1]
#print(path_root_path)
if root_path == path_root_path and (len(solspace[shortPath]) - 1 > i):
# make each overlapping edges of root path and path_root_path infinity, hence impossible to select
distances[spur_node][spur_node_plus_one] = float('inf')
distances[spur_node_plus_one][spur_node] = float('inf')
# Call Dijkstra function to compute spur path (the shortest path between spur node
# and end ignoring the i,i+1 edge
spur_path_a = dijkstra(nodes, distances, spur_node, end)
Compare this to wikipedia:
for each path p in A:
if rootPath == p.nodes(0, i):
// Remove the links that are part of the previous shortest paths which share the same root path.
remove p.edge(i, i + 1) from Graph;
for each node rootPathNode in rootPath except spurNode:
remove rootPathNode from Graph;
// Calculate the spur path from the spur node to the sink.
spurPath = Dijkstra(Graph, spurNode, sink);
You are meant to loop over paths in A and remove lots of edges from the graph before running Dijkstra.
However, in your code you call Dijkstra from within the loop that should be removing edges, therefore you will only ever run Dijkstra on a graph with a single edge removed and this limits the number of alternative routes you can find.
Try reducing the indent by 2 tab stops on the part that calls Dijkstra.
I'm having a hard time rounding off values in dicts. What I have is a list of dicts like this:
y = [{'a': 80.0, 'b': 0.0786235, 'c': 10.0, 'd': 10.6742903}, {'a': 80.73246, 'b': 0.0, 'c':
10.780323, 'd': 10.0}, {'a': 80.7239, 'b': 0.7823640, 'c': 10.0, 'd': 10.0}, {'a':
80.7802313217234, 'b': 0.0, 'c': 10.0, 'd': 10.9762304}]
I need to round off the values to just 2 decimal places.
When I try the following:
def roundingVals_toTwoDeci(y):
for d in y:
for k, v in d.items():
v = ceil(v*100)/100.0
print v
d[k] = v
return
roundingVals_toTwoDeci(y)
s = json.dumps(y)
print s
I get:
0.0
0.0
18.2
0.0
27.3
54.5
0.0
0.0
0.0
[{"a": 0.0, "b": 0.0, "c": 27.300000000000001, "d": 0.0, "e": 54.5, "f": 0.0, "g": 18.199999999999999, "h": 0.0, "i": 0.0}]
I need to make this work with versions 2.4+ and so am not using dict comprehensions.
First, I am having a hard time looping through all the key, values in all the dicts in the original.
Second, this result has just 1 decimal point instead of 2 when it prints inside the function?
Third, why is the 'json.dumps' and then 'print' not showing the values from inside the function?
EDIT:
Working with #Mark Ransom's answer below, I get the desired o/p. However, I have to urlencode the json.dumps value and send it to a URL. At the URL, it decodes the values into all the decimal places. So, for example, if, josn.dumps gives {"a": 9.1}, the URL shows it (after urlencode) as 9.10034254344365. The modified code is as below:
class LessPrecise(float):
def __repr__(self):
return str(self)
def roundingVals_toTwoDeci(y):
for d in y:
for k, v in d.items():
v = LessPrecise(round(v, 2))
print v
d[k] = v
roundingVals_toTwoDeci(y)
j = json.dumps(y)
print j
params = urllib.urlencode({'thekey': j})
print json.dumps gives {"a": 9.1}
At the URL after urlencode, it gives 9.1078667322034 instead of 9.1as in the following:
Output:::
100.0
0.0
0.0
0.0
100.0
0.0
0.0
0.0
81.8
0.0
18.2
0.0
90.0
0.0
0.0
10.0
[{"a": 100.0, "b": 0.0, "c": 0.0, "d": 0.0}, {"a": 100.0, "b": 0.0, "c": 0.0, "d": 0.0}, {"a":
81.8, "b": 0.0, "c": 18.2, "d": 0.0}, {"a": 90.0, "b": 0.0, "c": 0.0, "d": 10.0}]
At the URL:
9.100000381469727
The JSON string after json.dumps()
[{"a": 80.0, "b": 0.0, "c": 10.0, "d": 10.0}, {"a": 100.0, "b": 0.0, "c": 0.0, "d": 0.0}, {"a":
80.0, "b": 0.0, "c": 10.0, "d": 10.0}, {"a": 90.0, "b": 0.0, "c": 0.0, "d": 10.0}]
The urlencode string - after decoding at http://meyerweb.com/eric/tools/dencoder/
thekey=[{"a": 80.0, "b": 0.0, "c": 10.0, "d": 10.0}, {"a": 100.0, "b": 0.0, "c": 0.0, "d":
0.0}, {"a": 80.0, "b": 0.0, "c": 10.0, "d": 10.0}, {"a": 90.0, "b": 0.0, "c": 0.0, "d": 10.0}]
At the URL, I get values like 18.200000762939453(this value is from a later script run)
Taking the best bits from a couple of other answers:
class LessPrecise(float):
def __repr__(self):
return str(self)
def roundingVals_toTwoDeci(y):
for d in y:
for k, v in d.items():
v = LessPrecise(round(v, 2))
print v
d[k] = v
>>> roundingVals_toTwoDeci(y)
80.0
10.0
0.08
10.67
80.73
10.78
0.0
10.0
80.72
10.0
0.78
10.0
80.78
10.0
0.0
10.98
>>> s=json.dumps(y)
>>> s
'[{"a": 80.0, "c": 10.0, "b": 0.08, "d": 10.67}, {"a": 80.73, "c": 10.78, "b": 0.0, "d": 10.0}, {"a": 80.72, "c": 10.0, "b": 0.78, "d": 10.0}, {"a": 80.78, "c": 10.0, "b": 0.0, "d": 10.98}]'
JSONEncoder uses repr, and repr prints floats with all their available precision. The only possible solutions are to inherit from JSONEncoder and round while actually converting the values to a string (which implies to copy and adapt some code from the json.encoder module), or else wrap the floats into your own type RoundedFloat and register a serializer for that. Also note that repr's behaviour depends on the Python version used.
As often with non-obvious behaviour, the observation during debugging can trick you: print uses str(), and str() rounds at a certain point, unlike repr() which shows the naked ugliness of floating point maths.
The proof is in the code:
>>> class F(float):
... def __str__(self): return "str"
... def __repr__(self): return "repr"
...
...
>>> print F(1)
str
>>> F(1)
repr
>>> repr(1-1e-15)
'0.999999999999999'
>>> str(1-1e-15)
'1.0'
import json
y = [{'a': 80.0, 'b': 0.0786235, 'c': 10.0, 'd': 10.6742903}, {'a': 80.73246, 'b': 0.0, 'c':
10.780323, 'd': 10.0}, {'a': 80.7239, 'b': 0.7823640, 'c': 10.0, 'd': 10.0}, {'a':
80.7802313217234, 'b': 0.0, 'c': 10.0, 'd': 10.9762304}]
def roundingVals_toTwoDeci(y):
for d in y:
for k, v in d.items():
v = round(v,2) # <--- round() does exact that.
d[k] = v # <--- You need to put the rounded v back in d
print v
return
roundingVals_toTwoDeci(y)
s = json.dumps(y)
print s
Answering the second part of your question
Try replacing line 5 of your code with:
v = round(v, 2)
This will round the number to two decimal places. Using round, I get
[{'a': 80.0, 'c': 10.0, 'b': 0.08, 'd': 10.67}, {'a': 80.73, 'c': 10.78, 'b': 0.0, 'd': 10.0}, {'a': 80.72, 'c': 10.0, 'b': 0.78, 'd': 10.0}, {'a': 80.78, 'c': 10.0, 'b': 0.0, 'd': 10.98}]
I am using Python 2.7.2. Here's all the code:
from math import ceil
import json
y = [{'a': 80.0, 'b': 0.0786235, 'c': 10.0, 'd': 10.6742903},
{'a': 80.73246, 'b': 0.0, 'c': 10.780323, 'd': 10.0},
{'a': 80.7239, 'b': 0.7823640, 'c': 10.0, 'd': 10.0},
{'a': 80.7802313217234, 'b': 0.0, 'c': 10.0, 'd': 10.9762304}]
def roundingVals_toTwoDeci(y):
for d in y:
for k, v in d.items():
v = round(v, 2)
#print v
d[k] = v
return
roundingVals_toTwoDeci(y)
s = json.dumps(y)
print s
I don't understand what relates to json, but I can propose:
from math import ceil
y = [{'a': 80.0, 'b': 0.0786235, 'c': 10.0, 'd': 10.6742903},
{'a': 80.73246, 'b': 0.0, 'c': 10.780323, 'd': 10.0},
{'a': 80.7239, 'b': 0.7823640, 'c': 10.0, 'd': 10.0},
{'a': 80.7802313217234, 'b': 0.0, 'c': 10.0, 'd': 10.9762304}]
class TwoDec(float):
def __repr__(self):
return "%.2f" % self
def roundingVals_to_TwoDeci(y,ceil=ceil,TwoDec=TwoDec):
for d in y:
for k, v in d.iteritems():
d[k] = TwoDec(ceil(v*100)/100)
roundingVals_to_TwoDeci(y)
for el in y:
print el
result
{'a': 80.00, 'c': 10.00, 'b': 0.08, 'd': 10.68}
{'a': 80.74, 'c': 10.79, 'b': 0.00, 'd': 10.00}
{'a': 80.73, 'c': 10.00, 'b': 0.79, 'd': 10.00}
{'a': 80.79, 'c': 10.00, 'b': 0.00, 'd': 10.98}
I know this question is old, but here is a quick one-liner solution that works at least here in Linux Python 2.7.6 and might be interesting to someone else:
y = [{ x : round(z, 2) for x,z in yi.items()} for yi in y ]
However, this might be inefficient for larger data sets, as it re-generates the list/dict structure.
[[round(d[key],2) for key in d] for d in y]
[{key:round(d[key], 2) for key in d} for d in y]
Round dictionary values one-liner
with d as the dict and here to 2 decimal places
d = {k: round(v, 2) for k, v in d.items()}
Given the subject line Round off dict values to 2 decimals, this is what most will be coming here to find.
dictionary comprehension might be used in a search