Iterating through dictionaries and Accumulation - python

At the moment, I am attempting to accumulate values in dictionaries nested within a dictionary for homework purposes.
a = {
"Tennis Balls": {
"User Rating": 15,
"Available Colors": 5,
"Location": "Puppy Mart"
}
}
b = {
"Squeaky Toy": {
"User Rating": 48,
"Available Colors": 3,
"Location": "Pooch Shop"
}
}
c = {
"Stick": {
"User Rating": 32,
"Available Colors": 4,
"Location": "Pooch Shop"
}
}
d = {
"Old Shoe": {
"User Rating": 13,
"Available Colors": 2,
"Location": "Puppy Mart"
}
}
e = {
"Stuffed Animal": {
"User Rating": 14,
"Available Colors": 7,
"Location": "Dog Express"
}
}
puppy_toys = {"Toys": [a, b, c, d, e]}
total_user_ratings = 0
for toy in puppy_toys["Toys"]:
# insert your own code
individual_user_rating = puppy_toys["Toys"][toy]["User Rating"]
total_user_ratings += individual_user_rating
print(total_user_ratings)
I have to fill in # your line here with a single line of code that will allow the for loop to iterate through the dictionary puppy_toys and extract the total number of user ratings for toys located at "Pooch Shop", and then store the total in the variable total_user_ratings, but my line of code, shown below, doesn't seem to be working:
if["Location"] = "Pooch Shop":
Thanks for your assistance!

Well, after playing a little, I imagine you want to achieve the sum of User rating by name of Location, so, you have a dictionary with a list actually, correct me if I'm wrong, so you just have to loop it and take the values like this:
a = {
"Tennis Balls": {
"User Rating": 15,
"Available Colors": 5,
"Location": "Puppy Mart"
}
}
b = {
"Squeaky Toy": {
"User Rating": 48,
"Available Colors": 3,
"Location": "Pooch Shop"
}
}
c = {
"Stick": {
"User Rating": 32,
"Available Colors": 4,
"Location": "Pooch Shop"
}
}
d = {
"Old Shoe": {
"User Rating": 13,
"Available Colors": 2,
"Location": "Puppy Mart"
}
}
e = {
"Stuffed Animal": {
"User Rating": 14,
"Available Colors": 7,
"Location": "Dog Express"
}
}
puppy_toys = {"Toys": [a, b, c, d, e]}
total_user_ratings = 0
for toy in puppy_toys["Toys"]:
shop = list(toy.values())[0]
if (shop["Location"] == "Pooch Shop"):
individual_user_rating = shop["User Rating"]
total_user_ratings += individual_user_rating
print(total_user_ratings)

Your line of code has two main problems. Let's go over it:
if["Location"] = "Pooch Shop":
First, you are trying to compare between two expressions. This is done in python with the equality operator which is ==. A single = usually stands for assignment.
Ex:
>>> a = 5
>>> print(a)
5
>>> print(a == 5) # "is a equal to 5?"
True
The second problem is if["Location"].
In Python the square brackets usually are used as a "getter". A way to acces elements inside an object (like a list or a dictionary).
Ex:
>>> a = ["x", "y", "z"]
>>> print(a[1])
y
>>> b = {"name": "Tomer", "age": 29}
>>> print(b["name"])
Tomer
So you would want the ["Location"] to come after some object.
A hint for what that should be is in the next line of code:
individual_user_rating = puppy_toys["Toys"][toy]["User Rating"]

Related

Python get multiple specific keys and values from list of dictionaries

I have the following data:
data={
"locations": [
{
"id": "27871f2d-101c-449e-87ad-36a663b144fe",
"switch_id": 20,
"switch_port": 16,
"vlan_id": 101,
},
{
"id": "94b1d7a2-7ff2-4ba3-8259-5eb7ddd09fe1",
"switch_id": 6,
"switch_port": 24,
"vlan_id": 203,
},
]
}
And what I want to do is extract 'id' and 'vlan_id' into a new dictionary with a list of sub dictionaries, like this:
new_data={
"connections": [
{
"id": "27871f2d-101c-449e-87ad-36a663b144fe",
"vlan_id": 101,
},
{
"id": "94b1d7a2-7ff2-4ba3-8259-5eb7ddd09fe1",
"vlan_id": 203,
},
]
}
My initial thoughts were as a dictionary comprehension like this:
new_data = {"connections": [some code here]}
But not sure of the some code bit yet.
Try:
new_data = {"connections": [{'id': d['id'], 'vlan_id': d['vlan_id']} for d in data['locations']]}
{'connections': [{'id': '27871f2d-101c-449e-87ad-36a663b144fe', 'vlan_id': 101}, {'id': '94b1d7a2-7ff2-4ba3-8259-5eb7ddd09fe1', 'vlan_id': 203}]}
You can create the new_data variable accesing the first dictionary data like this:
new_data={
"connections": [
{
"id": data['locations'][0]['id'],
"vlan_id": data['locations'][0]['vlan_id'],
},
{
"id": data['locations'][1]['id'],
"vlan_id": data['locations'][1]['vlan_id'],
},
]
}
edit:
You can get a more dynamic approach by reading every object in the list with a forloop like this:
new_data={
"connections": []
}
for object in data['locations']:
new_dict = {
"id": object["id"],
"vlan_id": object["vlan_id"]
}
new_data['connections'].append(new_dict)
Following Marc's answer here, you could modify it to
new_data = {}
for i in range(len(data['locations'])):
if "connections" not in new_data.keys():
new_data['connections'] = [{"id": data['locations'][i]['id'],"vlan_id": data['locations'][i]['vlan_id']}]
else:
new_data['connections'].append({"id": data['locations'][i]['id'],"vlan_id": data['locations'][i]['vlan_id']})
The Answers here are good but you can make the code more dynamic
keys_to_extract = ['id', 'vlan_id']
locations = data['locations']
connections = { key: val for key, val in locations.items() if key in keys_to_extract }
new_data = {'connections': connections}
Now you can change the keys you need on the fly

Creating Lists from Multiple Jsons with Missing Keys

I am trying to create lists from json datas by pulling one by one and append them to the lists. However, some variables does not given in all json files. For example: for the json file below, data does not have ['statistics']['aerialLost'] , so it return Key Error. My Expected solution is when json file does not have key, append 'None' value to the list and continue.
Code
s_aerialLost = []
s_aerialWon = []
s_duelLost = []
s_duelWon = []
players = ['Martin Linnes', 'Christian Luyindama', 'Marcão', 'Ömer Bayram', 'Oghenekaro Etebo', 'Muhammed Kerem Aktürkoğlu', 'Gedson Fernandes', 'Emre Kılınç', 'Ryan Babel', 'Mostafa Mohamed', 'Florent Hadergjonaj', 'Tomáš Břečka', 'Duško Tošić', 'Oussama Haddadi', 'Kristijan Bistrović', 'Aytaç Kara', 'Haris Hajradinović', 'Armin Hodžić', 'Gilbert Koomson', 'Isaac Kiese Thelin']
players_id = [109569, 867191, 840951, 68335, 839110, 903324, 862055, 202032, 1876, 873551, 354860, 152971, 14557, 867180, 796658, 128196, 254979, 138127, 341107, 178743]
for player, player_id in zip(players, players_id):
url = base_url + str(player_id)
data = requests.request("GET", url).json()
## just added 4 data for simplify
accurateLongBalls = str(data['statistics']['accurateLongBalls'])
aerialLost = str(data['statistics']['aerialLost'])
aerialWon = str(data['statistics']['aerialWon'])
duelLost = str(data['statistics']['duelLost'])
s_aerialLost.append()
s_aerialWon.append()
s_duelLost.append()
s_duelWon.append()
Json File
{
"player": {
"name": "Martin Linnes",
"slug": "martin-linnes",
"shortName": "M. Linnes",
"position": "D",
"userCount": 339,
"id": 109569,
"marketValueCurrency": "€",
"dateOfBirthTimestamp": 685324800
},
"team": {
"name": "Galatasaray",
"slug": "galatasaray",
"shortName": "Galatasaray",
"gender": "M",
"userCount": 100254,
"nameCode": "GAL",
"national": false,
"type": 0,
"id": 3061,
"teamColors": {
"primary": "#ff9900",
"secondary": "#ff0000",
"text": "#ff0000"
}
},
"statistics": {
"totalPass": 32,
"accuratePass": 22,
"totalLongBalls": 7,
"accurateLongBalls": 3,
"totalCross": 2,
"aerialWon": 1,
"duelLost": 2,
"duelWon": 7,
"totalContest": 3,
"wonContest": 2,
"totalClearance": 4,
"totalTackle": 3,
"wasFouled": 1,
"fouls": 1,
"minutesPlayed": 82,
"touches": 63,
"rating": 7.3,
"possessionLostCtrl": 18,
"keyPass": 1
},
"position": "D"
}
Error
KeyError: 'aerialLost'
Use .get(). You can specify a default value to return if the key is not found, and it defaults to None.
So you can use
aerialLost = str(data.get('statistics', {}).get('aerialLost'))
The first call defaults to an empty dictionary so that there's something to make the second .get() call on. The second call just returns the default None.

Python - Print when a json object gets higher number

I want to create a script where I check a json file times to times using a while function. In there there is a json that looks like:
{
"names":[
{
"name":"hello",
"numbers":0
},
{
"name":"stack",
"numbers":1
},
{
"name":"over",
"numbers":2
},
{
"name":"flow",
"numbers":12
},
{
"name":"how",
"numbers":17
},
{
"name":"are",
"numbers":11
},
{
"name":"you",
"numbers":18
},
{
"name":"today",
"numbers":6
},
{
"name":"merry",
"numbers":4
},
{
"name":"x",
"numbers":1
},
{
"name":"mass",
"numbers":0
},
{
"name":"santa",
"numbers":4
},
{
"name":"hohoho",
"numbers":1
}
]
}
and what I want to do is that I want to check every number if numbers for each name has been increased than previous json look.
def script():
with open('data.json') as f:
old_data = json.load(f)
while True:
with open('data.json') as f:
new_data = json.load(f)
if old_data < new_data:
print("Bigger!!" + new_data['name'])
old_data = new_data
else:
randomtime = random.randint(5, 15)
print("Nothing increased")
old_data = new_data
time.sleep(randomtime)
Now I know that I have done it wrong and that's the reason I am here. I have no idea at this moment what I can do to make a sort of function where it checks numbers by numbers to see if its gotten bigger or not.
My question is:
How can I make it so it checks object by object to see if the numbers has gotten bigger from previous loop? and if it has not gotten bigger but lower, it should update the value of old_data and loops forever until the numbers has gotten bigger than previous loop?
EDIT:
Recommendation that I got from #Karl
{
'names': {
'hello': 0,
'stack': 0,
'over': 2,
'flow': 12,
'how': 17,
'are': 11,
'you': 18,
'today': 6,
'merry': 4,
'x': 1,
'mass': 0,
'santa': 4,
'hohoho': 1
}
}
Assuming your json is in this format:
{
"names": {
"hello": 0,
"stack": 1,
"over": 2,
"flow": 13,
"how": 17,
"are": 12,
"you": 18,
"today": 6,
"merry": 4,
"x": 1,
"mass": 0,
"santa": 4,
"hohoho": 1
}
}
I would do something along the following lines:
import json
import time
with open("data.json") as f:
old_data = json.load(f)["names"]
while True:
with open("data.json") as f:
new_data = json.load(f)["names"]
for name, number in new_data.items():
if number > old_data[name]:
print("Entry '{0}' has increased from {1} to {2}".format(name, old_data[name], number))
old_data = new_data
print("sleeping for 5 seconds")
time.sleep(5)
EDIT to answer question posted in comment "just curious, lets say if I want to add another value beside the numbers etc "stack": 1, yes (Yes and no to each of format), What would be needed to do in that case? (Just a script that I want to develop from this)".
In that case you should design your json input as follows:
{
"names": {
"hello": {
"number": 0,
"status": true
},
"stack": {
"number": 1,
"status": true
},
"over": {
"number": 2,
"status": false
},
...
}
}
You would need to change the lookups in the comparison script as follows:
for name, values in new_data.items():
if values["number"] > old_data[name]["number"]
(Note that for status you could also just have "yes" or "no" as inputs, but using booleans is must more useful when you have to represent a binary choice like this).
By the way, unless you aim to have objects other than names in this json, you can leave out that level and just make it:
{
"hello": {
"number": 0,
"status": true
},
"stack": {
"number": 1,
"status": true
},
"over": {
"number": 2,
"status": false
},
...
}
In that case, replace old_data = json.load(f)["names"] with old_data = json.load(f) and new_data= json.load(f)["names"] with new_data= json.load(f)
I took your original .json which you edited and presented in your question and re-factored your code to the below example. It appears to be working.
import time
import random
import json
path_to_file = r"C:\path\to\.json"
def script():
with open(path_to_file) as f:
d = json.load(f)
old_data = 0
for a_list in d.values():
for i in a_list:
print()
for d_keys, d_values in i.items():
print(d_keys, d_values)
if type(d_values) == int and d_values > old_data:
print("Bigger!!" + i['name'])
old_data = d_values
elif type(d_values) == int and d_values < old_data:
print("Nothing increased")
old_data = d_values
randomtime = random.randint(5, 15)
time.sleep(randomtime)
script()
This is the output I receive:
name hello numbers 0
name stack numbers 1 Bigger!!stack
name over numbers 2 Bigger!!over
name flow numbers 12 Bigger!!flow
name how numbers 17 Bigger!!how
name are numbers 11 Nothing increased
name you numbers 18 Bigger!!you
name today numbers 6 Nothing increased
name merry numbers 4 Nothing increased
name x numbers 1 Nothing increased
name mass numbers 0 Nothing increased
name santa numbers 4 Bigger!!santa
name hohoho numbers 1 Nothing increased

Foreach loop in Python to extract value from array in json response

I've got this json response:
{
"properties": {
"basic": {
"bandwidth_class": "",
"failure_pool": "",
"max_connection_attempts": 0,
"max_idle_connections_pernode": 50,
"max_timed_out_connection_attempts": 2,
"monitors": [
"Simple HTTP"
],
"node_close_with_rst": false,
"node_connection_attempts": 3,
"node_delete_behavior": "immediate",
"node_drain_to_delete_timeout": 0,
"nodes_table": [
{
"node": "abc1.prod.local:80",
"priority": 1,
"state": "active",
"weight": 1
},
{
"node": "def1.prod.local:80",
"priority": 1,
"state": "disabled",
"weight": 1
},
{
"node": "ghi1.prod.local:80",
"priority": 1,
"state": "disabled",
"weight": 1
},
{
"node": "jkl1.prod.local:80",
"priority": 1,
"state": "active",
"weight": 1
}
],
"note": "",
"passive_monitoring": true,
"persistence_class": "",
"transparent": false
}
}
}
And this powershell script:
$nodesAarray = "abc1.prod.local:80", "jkl1.prod.local:80"
foreach($node in $nodesArray)
{
$nodes_match_and_enabled = $GetNodesResponse.properties.basic.nodes_table | Where { $_.node -eq $node -and $_.state -eq "active" }
if($nodes_match_and_enabled)
{
Write-Output "$node exists in the pool and active"
}
else
{
Write-Output "$node is either not active or the name mismatches"
$global:invalidNodeArray.Add($node)
}
}
In my powershell script I am looping to check the two nodes in my array actually match by value and the state is active. It works as I expect.
However, I am scripting the same exact logic in Python (I am a beginner) but not sure how to approach it. Any idea what the script would look like in Python???
First, filter all active nodes, then compare with node list:
data = json.loads(text)
active_nodes = {
n['node']
for n in data['properties']['basic']['nodes_table']
if n['state'] == 'active'
}
nodes = {"abc1.prod.local:80", "jkl1.prod.local:80"}
for node in nodes:
if node in active_nodes:
print('{} exists in the pool and active'.format(node))
else:
print('{} is either not active or the name mismatches'.format(node))
invalid_nodes = nodes - active_nodes
Should work in Python 2 or 3, I think:
#!/usr/bin/env python
import sys
import json
res = ""
for line in sys.stdin:
res += line.rstrip()
res_obj = json.loads(res)
nodes = [ 'abc1.prod.local:80', 'jkl1.prod.local:80' ]
invalid_nodes = []
for node in nodes:
try:
found = False
test_node_objs = res_obj['properties']['basic']['nodes_table']
for test_node_obj in test_node_objs:
test_node = test_node_obj['node']
if node == test_node:
found = True
break
if found:
sys.stdout.write("%s exists in the pool and active\n" % (node))
else:
sys.stdout.write("%s is either not active or the name mismatches\n" % (node))
invalid_nodes.append(node)
except KeyError as ke:
sys.stderr.write("malformed response? check input...\n")
pass
Example usage:
$ ./parse_response.py < response.json
Here's an implementation:
jsonObj = json.loads(jsonSrc)
expectedNodes = {"abc1.prod.local:80", "jkl1.prod.local:80"}
for node in expectedNodes:
node_table = jsonObj['properties']['basic']['nodes_table']
node_match = list(filter(lambda t_node: node == t_node['node'], node_table))
is_node_matches_and_active = len(node_match) > 0 and node_match[0]['state'] == "active"
if is_node_matches_and_active:
print('node {} exists and is active'.format(node))
else:
print('node {} not found or not active'.format(node))
Output :
node jkl1.prod.local:80 exists and is active
node abc1.prod.local:80 exists and is active

I have Python list containing set of dictionaries, like a JSON representation. My task is to find no. of users against serial_ids.

Input data is like below.But, it actually contains thousands of dictionaries under this list and serial_ids are repeated throughout the list.
[{
"serial_id": 1,
"name": "ABC"
},
{
"serial_id": 6,
"name": "DEF"
},
{
"serial_id": 8,
"name": "GHI"
},
{
"serial_id": 0,
"name": "JKL"
},
{
"serial_id": 6,
"name": "VVV"
}]
Now, I know the range of serial_id but I don't want to hardcode it.
My task is to find the total number of users (i.e. name_count basically) per serial id. It will be better if I can get a table like structure sorted in descending order containing columns, serial_id and user_count per serial_id.
Questions are:
Can we make use of Dataframe concept? If possible, I would like to.
I am unable to get any method to achieve the required output.
Thanks in Advance !!
Since the JSON data is pulled from an API, below is the code I tried to but failed badly.
#Python libraries
import numpy as np
import pandas as pd
from pandas import DataFrame, Series
from collections import Counter
url1 = 'INPUT URL'
#print ('Retrieving',url1)
#uh = urllib2.urlopen(url1)
r = requests.get(url1)
r = r.text
#print r
#print ('Retrieved', len(r), 'characters')
try:js = json.loads(r) # js -> Native Python list
except:js = None
#print js
info = json.dumps(js , indent =4) #Prints out the JSON data in a nice format which we call as "Pretty Print"
#print (info)
'''
#print ('User Count:' , len(info))
for item in (js):
print ('Name' , item["name"])
'''
'''
user_count = 0
for item in (js):
#df = {'serial_id': Series[item["affiliate_id"]]} //ERROR
df = DataFrame({'serial_id': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]})
#Hard-coded the serial_id since we know the range of the affiliate_id
print(df)
Let's use Pandas dataframes:
from io import StringIO
import pandas as pd
jstring = StringIO("""[{
"serial_id": 1,
"name": "ABC"
},
{
"serial_id": 6,
"name": "DEF"
},
{
"serial_id": 8,
"name": "GHI"
},
{
"serial_id": 0,
"name": "JKL"
},
{
"serial_id": 6,
"name": "VVV"
}]""")
df = pd.read_json(jstring)
df_out = df.groupby('serial_id')['name'].count().reset_index(name='name_count')
print(df_out)
Output:
serial_id name_count
0 0 1
1 1 1
2 6 2
3 8 1

Categories