From a JSON file, with a list of dict, I'm trying to get data for each user and use them to create e new dict. Since each user has multiple objects, I'm interacting through them with a for loop. The start json looks like this:
[{
"obj_id": "bfyguwc9971",
"user_id": 3,
"investment": 34,
"profit": 67
},
{
"obj_id": "sdklgnv820",
"user_id": 12,
"investment": 71,
"profit": 43
}]
The JSON contains hundreds of these dictionaries, what I'm trying to achieve is to have a final dict with the avg investment and profit for each user.
Here is the code I'm running:
import json
with open('user_data.json','r') as f:
user_data = json.load(f)
users_id = []
users_dict = {}
obj_count = 0
investment_list = []
profit_list = []
for i in user_data:
if i['user_id'] not in users_id:
users_id.append(i['user_id'])
for a in users_id:
users_dict[a] = {}
for i in user_data:
if i['user_id'] == a:
obj_count += 1
users_dict[a]['Objects'] = obj_count
investment_list.append(i['investment'])
profit_list.append(i['profit'])
avg_investment = (sum(investment_list)/len(investment_list))
users_dict[a]['avg_investment'] = avg_investment
avg_profit = (sum(profit_list)/len(profit_list))
users_dict[a]['avg_profit'] = avg_profit
print(users_dict)
The problem occurs at the output, instead of giving me the right single values for each user, it give me back the first user values right and then it continues to add values for the next users, so the last user will have all the previous values calculated for the other users. What am I doing wrong? Thanks on advance for helping me!
Related
I have a dict like this:
contactos = dict([
"id", id,
"nombres", nombres,
"apellidos", apellidos,
"telefonos", telefonos,
"correos", correos
])
And it works when I put a new register in every key:value, my problem is, how can I get the record for only one contact?
I have a part where I can input a number and search the position in the list of the dict, then I want to only show the record of that specific record in every key:value
I made this code, but it doesn´t work.
telefo = input(Fore.LIGHTGREEN_EX + "TELEFONO CONTACTO: " + Fore.RESET)
for x in range(len(telefonos)):
if(telefonos[x] == telefo):
print(contactos["telefonos"][x])
else:
print("No encontrado")
I print only the telefono value, ´cause it´s my test code.
This should be your working script:
# I imagine your data to be somethig like this. If it isn't, sorry:
id = 0
nombres = ['John', 'Anna', 'Robert']
apellidos = ['J.', 'A.', 'Rob.']
telefonos = ['333-444', '222-111', '555-888']
correos = ['john#email.com', 'anna#email.com', 'rob#email.com']
# This is the part where you made it wrong.
# Dictionaries are created with {}
#
# [] creates a list, not a dictionary structure.
#
# Also, key and values must be grouped as:
# "key": value
contactos = dict({
"id": id,
"nombres": nombres,
"apellidos": apellidos,
"telefonos": telefonos,
"correos": correos
})
# Now, imagine this this is the input from user:
telefo = "333-444"
for x in range(len(telefonos)):
if (telefonos[x] == telefo):
print(contactos["telefonos"][x])
break
else:
print("No encontrado")
When testing the script, the output is 333-444.
I can't find a solution because the lack of understanding of programming.
I have created multiple Python Scripts where I do API calls to get results, the results are converted to JSON.
I want to store two specific fields from the JSON result for each user in an array, so I then later can make a "search" based of a users input(field), match it to the array and send a post request later.
The fields I want is: 'email' and 'userid', so when I search for the input (email) I can retrieve the userid, and send the post call from a button click.
So I understand that I can retrieve either email or userid by using the teo first lines to print the values. But the issue is when i try to store it in the array:
users = response.json()
print(users['user'][1]['userid']) #get user id
print(users['user'][1]['email']) #get email
json_length = len(users['user']) #get amount of users
print(json_length)
user_list = []
for i in users:
user_details = {"id":None, "email":None}
user_details['id'] = users['userid'][i]
user_details['email'] = users['email'][i]
user_list.append(user_details)
print(user_list)
I get the following error:
Exception has occurred: TypeError list indices must be integers or
slices, not str
File "C:...test2.py",
line 32, in
user_details['id'] = users['user'][i]['userid']
The JSON (multiple fields are removed and renamed)
{
"total":"2001",
"totalcount":"2",
"user":[
{
"userid":1,
"name":{
"firstname":"John",
"lastname":"Doe (Inactive)"
},
"email":"j.doe#something.com",
"status":"Inactive",
"organisation":{
"orgname":"something",
"orgid":1
},
},
{
"userid":2,
"name":{
"firstname":"Emma",
"lastname":"Hart (Inactive)"
},
"email":"e.hart#otherthing.com",
"status":"Inactive",
"organisation":{
"orgname":"otherthing",
"orgid":2
},
}
]
}
Any help for pointing what I'm doing wrong or help?
You're looping over the full JSON response keys, not the actual users list, then i would be each user object, so use that rather than the response again
Try
for i in users.get('user', []):
...
user_details['id'] = i['userid']
user_details['email'] = i['email']
You can also build that list in one line
user_list = [ {"id":u["userid"], "email":u["email"]} for u in users.get('user', []) ]
print(user_list)
So I am new to all this, please pardon my poor formatting and only loose grasp of jargon.
In short, I have a
coins = requests.get("https://bittrex.com/api/v1.1/public/getcurrencies")
that returns json() nested dictionaries (sorry for terrible phrasing) that look like this:
{
"success" : true,
"message" : "",
"result" : [{
"Currency" : "BTC",
"CurrencyLong" : "Bitcoin",
"MinConfirmation" : 2,
"TxFee" : 0.00020000,
"IsActive" : true,
"CoinType" : "BITCOIN",
"BaseAddress" : null
}, {
"Currency" : "LTC",
"CurrencyLong" : "Litecoin",
"MinConfirmation" : 5,
"TxFee" : 0.00200000,
"IsActive" : true,
"CoinType" : "BITCOIN",
"BaseAddress" : null
}]
}
In short I would like to access each dictionary within coins["result"] and build my own values with them to generate a class for each coin so that the inherited code gets filled, like:
class coinbuilder(self, currency, currencyLong, minConfirmation...):
def __init__(self):
self.currency = currency
self.currencyLong = currencyLong
ticker = requests.get("https://bittrex.com/api/v1.1/public/getticker?market=BTC-" + currency)
I understand this code is incorrect, but Im trying to give you an idea of what I am trying to accomplish. Sorry for my terrible phrasing, im new to programming in general and while I have a general grasp of function I am still trying to catch up on jargon.
There are several different ways to do this, you could parse the dictionary inside your __init__ function for example.
I tend to handle this by having a separate #classmethod that is responsible for parsing dictionaries to create instances of my class.
Something like this:
class Coinbuilder:
def __init__(self, cur, curlong):
self.currency = cur
self.currency_long = curlong
#classmethod
def build_from_dict(coin_b, d):
attributes = {'Currency', 'CurrencyLong'}
try:
class_dct = {a: d[a] for a in attributes}
except:
raise ValueError('Input did not contain necessary attributes')
return coin_b(class_dct['Currency'], class_dct['CurrencyLong'])
This way I am not forced to pass Coinbuilder a dictionary to create a class instance, but I have a simple method I can use to parse a dictionary to create an instance of my class.
For this simple example, I can do the following:
x = Coinbuilder.build_from_dict({'Currency': 'BTC', 'CurrencyLong': 'Bitcoin'})
Or I could use:
y = Coinbuilder('BTC', 'Bitcoin')
And get two equal class instances:
print(x.currency, x.currency_long)
print(y.currency, y.currency_long)
Output:
BTC Bitcoin
BTC Bitcoin
Using your sample input as a guide, once you write your #classmethod to parse your dictionary, you could then simply use:
my_coins = []
for result in coins['result']:
my_coins.append(Coinbuilder.build_from_dict(result))
Or:
my_coins = [Coinbuilder.build_from_dict(result) for result in coins['result']]
Here is a total script for what you are trying to do:
import requests
import json
class CoinBuilder:
def __init__(self,dict):
self.currency = dict['Currency']
self.currencyLong = dict['CurrencyLong']
self.minConfirmation = dict['MinConfirmation']
self.txFee = dict['TxFee']
self.isActive = dict['IsActive']
self.coinType = dict['CoinType']
self.baseAddress = dict['BaseAddress']
self.notice = dict['Notice']
coins_response = requests.get("https://bittrex.com/api/v1.1/public/getcurrencies")
all_coins = json.loads(coins_response.content)
list_of_coin_obs = []
for coin in all_coins["result"]:
list_of_coin_obs.append(CoinBuilder(coin))
This script is getting the response, then iterating through the dictionaries in result[] and building CoinBuilder objects from that. All of the created objects are also being stored in a list, list_of_coin_obs[].
You can then print the first 10 results you have, for example, like this:
# Print out the first 10 coins
print("First 10 coins:")
for i in range(1,11):
print(i,") ",list_of_coin_obs[i].currency)
For this example, this would output:
First 10 coins:
1 ) LTC
2 ) DOGE
3 ) VTC
4 ) PPC
5 ) FTC
6 ) RDD
7 ) NXT
8 ) DASH
9 ) POT
10 ) BLK
If you wanted to create a method to look up a specific coin by it's ticker symbol, you could create something like this:
# method to retrieve a specific coin from 'list_of_coin_obs[]'
# we are passing in a parameter, 'coin_abr' to give to our filter
def get_specific_coin_by_abr(coin_abr):
return next(filter(lambda x: x.currency == coin_abr, list_of_coin_obs))
# call our method, which returns a 'CoinBuilder' type
specific_coin = get_specific_coin_by_abr('BTC')
# print our results to show it worked
print('CurrencyName: ',specific_coin.currency,'CurrencyLong: ',specific_coin.currencyLong)
This prints:
CurrencyName: BTC CurrencyLong: Bitcoin
Note: This is assuming that you already have the list_of_coin_obs[] created and in the same scope as this method.
One suggestion, here the class name CoinBuilder doesn't totally make the most sense. A better name for the class/objects would simply be Coin or NamedCurrency or some other similar name. I think I know what you were going for, but this is probably a better fit for your project.
Best of luck.
Here is a class that analyses data:
class TopFive:
def __init__(self, catalog_data, sales_data, query, **kwargs):
self.catalog_data = catalog_data
self.sales_data = sales_data
self.query = query
def analyse(self):
CATALOG_DATA = self.catalog_data
SALES_DATA = self.sales_data
query = self.query
products = {}
# Creating a dict with ID, city or hour ( depending on query ) as keys and their income as values.
for row in SALES_DATA:
QUERIES = {
'category': row[0],
'city': row[2],
'hour': row[3]
}
if QUERIES[query] in products:
products[QUERIES[query]] += float(row[4])
products[QUERIES[query]] = round(products[QUERIES[query]], 2)
else:
products[QUERIES[query]] = float(row[4])
if query == 'category':
top_five = {}
top_five_items = sorted(products, key=products.get, reverse=True)[:5] # Getting top 5 categories.
for key in top_five_items:
for row in CATALOG_DATA:
if key == row[0]:
key_string = row[5] + ', ' + row[4]
top_five[key_string] = products[key]
return top_five
else:
return products
It is being called like so:
holder = TopFive(catalog_data=catalog_data, sales_data=sales_data, query='hour')
top_hour = holder.analyse()
What I want to do now is work with the dates. They come in from an input csv file looking like this:
2015-12-11T17:14:05+01:00
Now I need to change to UTC time zone. I thought of using:
.astimezone(pytz.utc)
And now to my question: Can I somehow do so in my QUERIES dictionary, so that when the 'hour' argument is passed to the class I can then execute the program, without changing the following code's structure:
if QUERIES[query] in products:
products[QUERIES[query]] += float(row[4])
products[QUERIES[query]] = round(products[QUERIES[query]], 2)
else:
products[QUERIES[query]] = float(row[4])
and without adding more conditions.
I am thinking of something like:
'hour': row[3].astimezone(pytz.utc)
But this is not working. I can understand why, I am just wondering if there is a similar approach that works. Otherwise I would have to add yet another condition with separate return value and work there.
Got it! The answer to my question is yes: you can use methods in dictionary, just as I tried:
QUERIES = {
'category': row[0],
'city': row[2],
'hour': hour.astimezone(pytz.utc)
}
What I just realized was that I forgot to parse the csv input into datetime format. So obviously when I try to use .astimezone on string it raises error. Sorry for the long useless post, but I'm still very new to OOP and its quite difficult keeping track of all files, instances and so on ;D Thanks
How do I look up the 'id' associated with the a person's 'name' when the 2 are in a dictionary?
user = 'PersonA'
id = ? #How do I retrieve the 'id' from the user_stream json variable?
json, stored in a variable named "user_stream"
[
{
'name': 'PersonA',
'id': '135963'
},
{
'name': 'PersonB',
'id': '152265'
},
]
You'll have to decode the JSON structure and loop through all the dictionaries until you find a match:
for person in json.loads(user_stream):
if person['name'] == user:
id = person['id']
break
else:
# The else branch is only ever reached if no match was found
raise ValueError('No such person')
If you need to make multiple lookups, you probably want to transform this structure to a dict to ease lookups:
name_to_id = {p['name']: p['id'] for p in json.loads(user_stream)}
then look up the id directly:
id = name_to_id.get(name) # if name is not found, id will be None
The above example assumes that names are unique, if they are not, use:
from collections import defaultdict
name_to_id = defaultdict(list)
for person in json.loads(user_stream):
name_to_id[person['name']).append(person['id'])
# lookup
ids = name_to_id.get(name, []) # list of ids, defaults to empty
This is as always a trade-off, you trade memory for speed.
Martijn Pieters's solution is correct, but if you intend to make many such look-ups it's better to load the json and iterate over it just once, and not for every look-up.
name_id = {}
for person in json.loads(user_stream):
name = person['name']
id = person['id']
name_id[name] = id
user = 'PersonA'
print name_id[user]
persons = json.loads(...)
results = filter(lambda p:p['name'] == 'avi',persons)
if results:
id = results[0]["id"]
results can be more than 1 of course..