Converting nested List to Dictionary | Python - python-3.x

I have made a list comprehension that generates mock fingerprint data.
import random
val = [[hand, [digit, [[random.randint(1, 250) for i in range(0, 8)] for j in range(0, 4)]]] for hand in ['Left', 'Right'] for digit in ['Thumb', 'Index', 'Middle', 'Ring', 'Little']]
val
>>> [['Left',
['Thumb',
[[247, 115, 74, 161, 47, 31, 231, 34],
[246, 52, 1, 160, 196, 65, 4, 118],
[128, 219, 128, 140, 207, 2, 156, 226],
[127, 61, 56, 151, 169, 122, 117, 105]]]]
...
['Right',
['Thumb',
[[229, 222, 138, 230, 86, 119, 201, 209],
[106, 238, 191, 15, 214, 134, 77, 145],
[186, 174, 81, 143, 138, 5, 54, 148],
[176, 85, 205, 235, 228, 204, 91, 17]]]]
Note: "digit" means finger name.
Based on this list output, I would like to convert it to a dictionary of the below structure.
I've been unable to make a dictionary comprehension that would yield the desired output:
{
"Left":
{
"Thumb": [...],
"Index": [...],
"Middle": [...],
"Ring": [...],
"Little": [...]
},
"Right":
{
"Thumb": [...],
"Index": [...],
"Middle": [...],
"Ring": [...],
"Little": [...]
}
}
Note: I understand my above dictionary "output" is somewhat incorrect.
I'm using Jupyter Notebooks. Best attempt:
output = {hand: {digit: matrix for i in val for hand in val[i] for digit in hand}}
output
>>> ---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-46-500095a8cf85> in <module>
----> 1 output = {hand: {digit: matrix for i in val for hand in val[i] for digit in hand}}
2 output
NameError: name 'hand' is not defined

You can just create the structure directly with a dict comprehension.
import random
output = {
hand: {
digit: [
random.randint(1, 250) for _ in range(0, 8)
] for digit in ['Thumb', 'Index', 'Middle', 'Ring', 'Little']
} for hand in ['Left', 'Right']
}
print(output)
The trick to nested comprehensions is to create your inner-most structure first and work outwards from there.
So create your inner list,
inner = [random.randint(1, 250) for _ in range(0, 8)]
Then your dict of digits.
digits = {digit: inner for digit in ['Thumb', 'Index', 'Middle', 'Ring', 'Little']}
And lastly your dict of hands.
hands = {hand: digits for hand in ['Left', 'Right']}
Combine those all together and you get.
{
hand: {
digit: [
random.randint(1, 250) for _ in range(0, 8)
] for digit in ['Thumb', 'Index', 'Middle', 'Ring', 'Little']
} for hand in ['Left', 'Right']
}

Related

How to display name and grade for a student in a dictiionary who has the highest grade

I'm a brand new to programming and I'm stuck on a practice exercise.
EDIT: exact error code "avgDict[k] =max(sum(v)/ float(len(v)))
TypeError: 'float' object is not iterable"
If I remove max it's printing every student's avg.
# student_grades contains scores (out of 100) for 5 assignments
diction = {
'Andrew': [56, 79, 90, 22, 50],
'Colin': [88, 62, 68, 75, 78],
'Alan': [95, 88, 92, 85, 85],
'Mary': [76, 88, 85, 82, 90],
'Tricia': [99, 92, 95, 89, 99]
}
def averageGrades(diction):
avgDict = {}
for k, v in diction.items():
avgDict[k] =max(sum(v)/ float(len(v)))
return avgDict
What your code is doing right now is iterating through each key-value pair of the dictionary (where the key is the student's name and the value is the list of the student's grades), and then calculating the average for the student. Then, the way you are using max right now, it is trying to find the max of a single student's average. This is why you are receiving the error, because max expects either an iterable or multiple parameters, and a float (which is the value produced by sum(v) / float(len(v))) is not an iterable. You should instead compute all of the averages first, and then find the max value in the dictionary of averages:
diction = {
'Andrew': [56, 79, 90, 22, 50],
'Colin': [88, 62, 68, 75, 78],
'Alan': [95, 88, 92, 85, 85],
'Mary': [76, 88, 85, 82, 90],
'Tricia': [99, 92, 95, 89, 99]
}
def averageGrades(diction):
avgDict = {}
for k, v in diction.items():
avgDict[k] = sum(v) / len(v)
return max(avgDict.items(), key=lambda i: i[1]) # find the pair which has the highest value
print(averageGrades(diction)) # ('Tricia', 94.8)
Sidenote, in Python 3, using / does normal division (as opposed to integer division) by default, so casting len(v) to a float is unnecessary.
Alternatively, if you don't need to create the avgDict variable, you can just determine the max directly without the intermediate variable:
def averageGrades(diction):
return max([(k, sum(v) / len(v)) for k, v in diction.items()], key=lambda i: i[1])
print(averageGrades(diction)) # ('Tricia', 94.8)

Matplotlib scatter plot how to give same color for same size

I am having two arrays and a difference arrays of first two arrays
X = [1, 5, 63, 77, 103, 148, 156, 177, 183]
Y = [3, 46, 65, 87, 129, 150, 166, 181, 186]
Diff = [ 2 41 2 10 26 2 10 4 3 3]
How to plot a scatter plot for this data with x,y,diff where the same difference value show same color using matplotlib in python?
You should use 'c' parameter to color the differences.
Please see the below code:
X = [1, 5, 63, 77, 103, 148, 156, 177, 183]
Y = [3, 46, 65, 87, 129, 150, 166, 181, 186]
Diff = [ 2, 41, 2, 10, 26, 2, 10, 4, 3]
import matplotlib.pyplot as plt
plt.scatter(X,Y,c=Diff)

Using Capacity Constraint with Pickup and Delivery

Being new to OR-Tools libraries I am unable to modify the existing code for my requirements. I have a requirement to add capacity constraint with pickup and delivery i.e a person will deliver items items as mentioned in pickup and delivery algo, but there will be a constraint how much items he can accommodate with him. I tried using code for capacity constraint with pickup and delivery code, but didn't get success. Here is a sample code:
from __future__ import print_function
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
def create_data_model():
"""Stores the data for the problem."""
data = {}
data['distance_matrix'] = [
[
0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388, 354,
468, 776, 662
],
[
548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480, 674,
1016, 868, 1210
],
[
776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278, 1164,
1130, 788, 1552, 754
],
[
696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628, 822,
1164, 560, 1358
],
[
582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514, 708,
1050, 674, 1244
],
[
274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662, 628,
514, 1050, 708
],
[
502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890, 856,
514, 1278, 480
],
[
194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354, 320,
662, 742, 856
],
[
308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810, 696, 662,
320, 1084, 514
],
[
194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 536, 422, 388,
274, 810, 468
],
[
536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878, 764,
730, 388, 1152, 354
],
[
502, 594, 1278, 514, 400, 776, 1004, 468, 810, 536, 878, 0, 114,
308, 650, 274, 844
],
[
388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0, 194,
536, 388, 730
],
[
354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194, 0,
342, 422, 536
],
[
468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650, 536,
342, 0, 764, 194
],
[
776, 868, 1552, 560, 674, 1050, 1278, 742, 1084, 810, 1152, 274,
388, 422, 764, 0, 798
],
[
662, 1210, 754, 1358, 1244, 708, 480, 856, 514, 468, 354, 844, 730,
536, 194, 798, 0
],
]
data['pickups_deliveries'] = [
[1, 6],
[2, 10],
[4, 3],
[5, 9],
[7, 8],
[15, 11],
[13, 12],
[16, 14],
]
data['num_vehicles'] = 4
data['depot'] = 0
data['vehicle_capacities'] = [15,15,15,15]
data['demands'] = [0, 1, 1, 3, 6, 3, 6, 8, 8, 1, 2, 1, 2, 6, 6, 8, 8]
return data
def print_solution(data, manager, routing, assignment):
"""Prints assignment on console."""
total_distance = 0
total_load = 0
for vehicle_id in range(data['num_vehicles']):
index = routing.Start(vehicle_id)
plan_output = 'Route for vehicle {}:\n'.format(vehicle_id)
route_distance = 0
route_load = 0
while not routing.IsEnd(index):
node_index = manager.IndexToNode(index)
route_load += data['demands'][node_index]
plan_output += ' {0} Load({1}) -> '.format(node_index, route_load)
previous_index = index
index = assignment.Value(routing.NextVar(index))
route_distance += routing.GetArcCostForVehicle(
previous_index, index, vehicle_id)
plan_output += ' {0} Load({1})\n'.format(manager.IndexToNode(index),
route_load)
plan_output += 'Distance of the route: {}m\n'.format(route_distance)
plan_output += 'Load of the route: {}\n'.format(route_load)
print(plan_output)
total_distance += route_distance
total_load += route_load
print('Total distance of all routes: {}m'.format(total_distance))
print('Total load of all routes: {}'.format(total_load))
def main():
"""Entry point of the program."""
# Instantiate the data problem.
data = create_data_model()
# Create the routing index manager.
manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),
data['num_vehicles'], data['depot'])
# Create Routing Model.
routing = pywrapcp.RoutingModel(manager)
# Define cost of each arc.
def distance_callback(from_index, to_index):
"""Returns the manhattan distance between the two nodes."""
# Convert from routing variable Index to distance matrix NodeIndex.
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return data['distance_matrix'][from_node][to_node]
transit_callback_index = routing.RegisterTransitCallback(distance_callback)
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
# Add Capacity constraint.
def demand_callback(from_index):
"""Returns the demand of the node."""
# Convert from routing variable Index to demands NodeIndex.
from_node = manager.IndexToNode(from_index)
return data['demands'][from_node]
demand_callback_index = routing.RegisterUnaryTransitCallback(
demand_callback)
routing.AddDimensionWithVehicleCapacity(
demand_callback_index,
0, # null capacity slack
data['vehicle_capacities'], # vehicle maximum capacities
True, # start cumul to zero
'Capacity')
# Add Distance constraint.
dimension_name = 'Distance'
routing.AddDimension(
transit_callback_index,
0, # no slack
3000, # vehicle maximum travel distance
True, # start cumul to zero
dimension_name)
distance_dimension = routing.GetDimensionOrDie(dimension_name)
distance_dimension.SetGlobalSpanCostCoefficient(100)
# Define Transportation Requests.
for request in data['pickups_deliveries']:
pickup_index = manager.NodeToIndex(request[0])
delivery_index = manager.NodeToIndex(request[1])
routing.AddPickupAndDelivery (pickup_index, delivery_index)
routing.solver().Add(routing.VehicleVar(pickup_index) == routing.VehicleVar(delivery_index))
routing.solver().Add(distance_dimension.CumulVar(pickup_index) <= distance_dimension.CumulVar(delivery_index))
# Setting first solution heuristic.
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION)
# Solve the problem.
assignment = routing.SolveWithParameters(search_parameters)
print(assignment)
# Print solution on console.
if assignment:
print("1")
print_solution(data, manager, routing, assignment)
if __name__ == '__main__':
main()
There is no solution because the total demand is greater than the total vehicle capacity. The demand is 70 the capacity is 60.
For anyone having trouble getting a solution to this problem, I'll just leave it here instead of creating a new question and writing the solution myself. There might be something in this answer you might've missed.
Lets first understand how capacity constraint works in plain English
What is the demands array?
It is a unit of quantity which the vehicle will have to carry upon going to that location.
What is the vehicle_capacities array?
It is the maximum quantity in units which a particular vehicle can carry.
Now moving on to pickup & delivery
In this case however, our 'vehicles' don't carry an additional weight/quantity (in units) upon reaching the delivery location. Instead, it will release the quantity (in units) which it carried from the pickup location.
So, our demands array will change accordingly.
Considering this is our pickup_deliveries array
data['pickups_deliveries'] = [
[1, 6],
[2, 10],
[4, 3],
[5, 9],
[7, 8],
[15, 11],
[13, 12],
[16, 14],
]
Our demands array should look something like:
data['demands'] = [0, 1, 2, -6, 6, 10, -1, 8, -8, -10, -2, -9, -4, 4, -13, 9, 13]
Where each delivery location will release that same amount of quantity which we picked up from the pickup location.
Side Note (Not related to question but might help you)
When using pickup and delivery with capacity constraint or combining it with any other constraint like time window or even multiple start end, it makes the job a whole lot easier if we first specify depots and then pickup1 then drop1, then pickup2 then drop2, etc.
Eg:
data['num_vehicles'] = 4
# put all vehicles at the start of your 'addresses' array (i.e. they will be the first rows in the distance / time matrices)
data['starts'] = [0, 1, 2, 3]
data['ends'] = [0, 1, 2, 3]
# then simply, from the next 2 indices start defining the pickups and drops
# i.e. 4 is pickup1 5 is drop1, 6 is pickup2 7 is drop2, etc. (this also makes it easier for dynamic input)
# i.e. if num_vehicles is 3 -> next 2 -> 3,4 (since index starts from 0)
data['pickups_deliveries'] = [
[4, 5],
[6, 7],
[8, 9],
[10, 11],
[12, 13],
[14, 15]
]
# then 0 to num_vehicle values will be 0 (since depots won't have weight in normal condition unless you have something...)
# and the rest of the numbers will be pairs of pickups and drop weights i.e. what is picked up is dropped so (num,-num) for 1 pickup-drop pair etc.
data['demands'] = [0, 0, 0, 0, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1]
data['vehicle_capacities'] = [1, 1, 1, 1] # this depends on your problem.
# here I have considered that a vehicle can only carry one thing at a time

conversion of string to tuple in python

I have a tuple (h) as follows:
(array([[145, 34, 26, 18, 90, 89],
[ 86, 141, 216, 167, 67, 214],
[ 18, 0, 212, 49, 232, 34],
...,
[147, 99, 73, 110, 108, 9],
[222, 133, 231, 48, 227, 154],
[184, 133, 169, 201, 162, 168]], dtype=uint8), array([[178, 58, 24, 90],
[ 3, 31, 129, 243],
[ 48, 92, 19, 108],
...,
[148, 21, 25, 209],
[189, 114, 46, 218],
[ 15, 43, 92, 61]], dtype=uint8), array([[ 17, 254, 216, ..., 126, 74, 129],
[231, 168, 214, ..., 131, 50, 107],
[ 77, 185, 229, ..., 86, 167, 61],
...,
[105, 240, 95, ..., 230, 158, 27],
[211, 46, 193, ..., 48, 57, 79],
[136, 126, 235, ..., 109, 33, 185]], dtype=uint8))
I converted it into a string s = str(h):
'(array([[ 1, 60, 249, 162, 51, 3],\n [ 57, 76, 193, 244, 17, 238],\n [ 22, 72, 101, 229, 185, 124],\n ...,\n [132, 243, 123, 192, 152, 107],\n [163, 187, 131, 47, 253, 155],\n [ 21, 3, 77, 208, 229, 15]], dtype=uint8), array([[119, 149, 215, 129],\n [146, 71, 121, 79],\n [114, 148, 121, 140],\n ...,\n [175, 121, 81, 71],\n [178, 92, 1, 99],\n [ 80, 122, 189, 209]], dtype=uint8), array([[ 26, 122, 248, ..., 104, 167, 29],\n [ 41, 213, 250, ..., 82, 71, 211],\n [ 20, 122, 4, ..., 152, 99, 121],\n ...,\n [133, 77, 84, ..., 238, 243, 240],\n [208, 183, 187, ..., 182, 51, 116],\n [ 19, 135, 48, ..., 210, 163, 58]], dtype=uint8))'
Now, I want to convert s back to a tuple. I tried using ast.literal_eval(s), but I get the following error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.5/ast.py", line 84, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.5/ast.py", line 55, in _convert
return tuple(map(_convert, node.elts))
File "/usr/lib/python3.5/ast.py", line 83, in _convert
raise ValueError('malformed node or string: ' + repr(node))
ValueError: malformed node or string: <_ast.Call object at 0x76a6f770>
I could not find this exact solution anywhere. It would be great if someone could help me out.
You can't use str() on numpy arrays (wrapped in tuples or otherwise) and hope to recover the data.
First of all, the ast.literal_eval() function only supports literals and literal displays, not numpy array(...) syntax.
Next, str() on a tuple produces debugging-friendly output; tuples don't implement a __str__ string conversion hook, so their repr() representation is returned instead. Numpy arrays do support str() conversion, but their output is still but a friendly-looking string that omits a lot of detail from the actual values. In your example, those ... ellipsis dots indicate that there is more data in that part of the array, but the strings do not include those values. So you are losing data if you were to try to re-create your arrays from this.
If you need to store these tuples in a file or database column, or need to transmit them over a network connection, you need to serialise the data. Proper serialisation will preserve every detail of the arrays.
For tuples with numpy arrays, you can use pickle.dumps() to produce a bytes object that can be passed back to pickles.loads() to recreate the same value.
You can also convert invidual numpy arrays to a numpy-specific binary format, and load that format again, with the numpy.save() and numpy.load() functions (which operate directly on files, but you can pass in io.BytesIO() objects).

ValueError for a matplotlib contour plot in Python

I receive "ValueError: setting an array element with a sequence" when running. I have tried to turn everything into a numpy array to no avail.
import matplotlib
import numpy as np
from matplotlib import pyplot
X=np.array([
np.array([1,2,3,4,5,6,7]),
np.array([1,2,3,4,5,6,7]),
np.array([1,2,3,4,5,6,6.5,7.5]),
np.array([1,2,3,4,5,6,7,8]),
np.array([1,2,3,4,5,6,7,8,8.5]),
np.array([1,2,3,4,5,6,7,8]),
np.array([1,2,3,4,5,6,7])])
Y=np.array([
np.array([1,1,1,1,1,1,1]),
np.array([2,2,2,2,2,2,2]),
np.array([3,3,3,3,3,3,2.5,3]),
np.array([4,4,4,4,4,4,4,4]),
np.array([5,5,5,5,5,5,5,5,5]),
np.array([6,6,6,6,6,6,6,6]),
np.array([7,7,7,7,7,7,7])])
Z= np.array([
np.array([4190, 4290, 4200, 4095, 4181, 4965, 4995]),
np.array([4321, 4389, 4311, 4212, 4894, 4999, 5001]),
np.array([4412, 4442, 4389, 4693, 4899, 5010, 5008, 4921]),
np.array([4552, 4651, 4900, 4921, 4932, 5020, 4935, 4735]),
np.array([4791, 4941, 4925, 5000, 4890, 4925, 4882, 4764, 4850]),
np.array([4732, 4795, 4791, 4852, 4911, 4865, 4919, 4862]),
np.array([4520, 4662, 4735,4794,4836,4852,4790])])
matplotlib.pyplot.contour(X, Y, Z)
EDIT
I sort of solved this problem by removing values from my sub-arrays in order to make the lengths equal, however I would still like to know how it is possible to feed an array containing sub-arrays of different lengths into contour plot.
The answer is to make X, Y and Z inputs all 1D arrays and to use tricontour instead of contour.
X=np.array([1,2,3,4,5,6,7,
1,2,3,4,5,6,7,
1,2,3,4,5,6,6.5,7.5,
1,2,3,4,5,6,7,8,
1,2,3,4,5,6,7,8,9,
1,2,3,4,5,6,7,8,
1,2,3,4,5,6,7])
Y=np.array([1,1,1,1,1,1,1,
2,2,2,2,2,2,2,
3,3,3,3,3,3,2.5,3,
4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7])
Z= np.array([80, 73, 65, 57, 61, 55, 60,
78, 73, 71, 55, 55, 60, 90,
65, 62, 61, 61, 51, 60, 71, 78,
70, 58, 58, 65, 80, 81, 90, 81,
80, 59, 51, 58, 70, 70, 90, 89, 78,
90, 63, 55, 58, 65, 78, 79, 70,
100, 68, 54,52,60,72,71])
Y=np.flip(Y,0)
asdf=matplotlib.pyplot.tricontour(X, Y, Z,11)
matplotlib.pyplot.xlim([1,8])
matplotlib.pyplot.ylim([1,7])
matplotlib.pyplot.clabel(asdf, fontsize=6, inline=0)
matplotlib.pyplot.show()

Resources