Before writing a function, I would like to be sure there is no pre-built (optimized) solution (like sorted()) that can:
From a dictionary like this one :
tags = {'pinoyako':{'likes': 119, 'comments': 11, 'count': 1}, 'dii':{'likes': 151, 'comments': 3, 'count': 1},'djiphantom3':{'likes': 127, 'comments': 6, 'count': 1}}
Order the keys based on 'likes', 'comments' or 'count'. If it's based on 'likes', the output should be a list ordered :
output = [['dii',151],['djiphantom3',127],['pinoyako',119]]
Use a generator expression within sorted() function with a proper key function:
In [22]: from operator import itemgetter
In [23]: sorted(((k, v['likes']) for k, v in tags.items()), key=itemgetter(1), reverse=True)
Out[23]: [('dii', 151), ('djiphantom3', 127), ('pinoyako', 119)]
You need more entries to illustrate. Check this:
tags = {'pinoyako':{'likes': 119, 'comments': 11, 'count': 1},
'pinoyako2':{'likes': 120, 'comments': 5, 'count': 2},
'djiphantom32':{'likes': 1275, 'comments': 61, 'count': 15},
'dii2':{'likes': 151, 'comments': 33, 'count': 13},
'dii':{'likes': 151, 'comments': 3, 'count': 1},
'djiphantom3':{'likes': 1275, 'comments': 61, 'count': 1}
}
tags_sorted = sorted(tags.items(), key=lambda x: (x[1]['likes'], x[1]['comments'], x[1]['count']))
tags_sorted
Output:
[('pinoyako', {'comments': 11, 'count': 1, 'likes': 119}),
('pinoyako2', {'comments': 5, 'count': 2, 'likes': 120}),
('dii', {'comments': 3, 'count': 1, 'likes': 151}),
('dii2', {'comments': 33, 'count': 13, 'likes': 151}),
('djiphantom3', {'comments': 61, 'count': 1, 'likes': 1275}),
('djiphantom32', {'comments': 61, 'count': 15, 'likes': 1275})]
Then you can do this:
tags_sorted = [[k, v['likes']] for k,v in tags_sorted]
tags_sorted
Output:
[['pinoyako', 119],
['pinoyako2', 120],
['dii', 151],
['dii2', 151],
['djiphantom3', 1275],
['djiphantom32', 1275]]
Related
I want to iterate through a dictionary array like the following to only copy the 'symbol' and 'product_progress' keys and their corresponding values to new dictionary array.
[{'coin_name': 'Bitcoin', 'coin_id': 'bitcoin', 'symbol': 'btc', 'rank': 1, 'product_progress': 93, 'team': 100, 'token_fundamentals': 100, 'github_activity': 95, 'marketing': 5, 'partnership': 5, 'uniqueness': 5, 'total_score': 96, 'exchange_name': 'Bitfinex', 'exchange_link': 'https://www.bitfinex.com/t/BTCUSD', 'website': 'https://bitcoin.org/en/', 'twitter': 'https://twitter.com/Bitcoin', 'telegram': None, 'whitepaper': 'https://bitcoin.org/en/bitcoin-paper'}, {'coin_name': 'Ethereum', 'coin_id': 'ethereum', 'symbol': 'eth', 'rank': 2, 'product_progress': 87, 'team': 98, 'token_fundamentals': 97, 'github_activity': 100, 'marketing': 5, 'partnership': 5, 'uniqueness': 5, 'total_score': 94, 'exchange_name': 'Gemini', 'exchange_link': 'https://gemini.com/', 'website': 'https://www.ethereum.org/', 'twitter': 'https://twitter.com/ethereum', 'telegram': None, 'whitepaper': 'https://ethereum.org/en/whitepaper/'}] ...
The code I have so far is:
# need to iterate through list of dictionaries
for index in range(len(projectlist3)):
for key in projectlist3[index]:
d['symbol'] = projectlist3[index]['symbol']
d['token_fundamentals'] = projectlist3[index]['token_fundamentals']
print(d)
It's just saving the last entry rather than all of the entries {'symbol': 'eth', 'token_fundamentals': 97}
Given your data:
l = [{
'coin_name': 'Bitcoin',
'coin_id': 'bitcoin',
'symbol': 'btc',
'rank': 1,
'product_progress': 93,
'team': 100,
'token_fundamentals': 100,
'github_activity': 95,
'marketing': 5,
'partnership': 5,
'uniqueness': 5,
'total_score': 96,
'exchange_name': 'Bitfinex',
'exchange_link': 'https://www.bitfinex.com/t/BTCUSD',
'website': 'https://bitcoin.org/en/',
'twitter': 'https://twitter.com/Bitcoin',
'telegram': None,
'whitepaper': 'https://bitcoin.org/en/bitcoin-paper'
}, {
'coin_name': 'Ethereum',
'coin_id': 'ethereum',
'symbol': 'eth',
'rank': 2,
'product_progress': 87,
'team': 98,
'token_fundamentals': 97,
'github_activity': 100,
'marketing': 5,
'partnership': 5,
'uniqueness': 5,
'total_score': 94,
'exchange_name': 'Gemini',
'exchange_link': 'https://gemini.com/',
'website': 'https://www.ethereum.org/',
'twitter': 'https://twitter.com/ethereum',
'telegram': None,
'whitepaper': 'https://ethereum.org/en/whitepaper/'
}]
You can use listcomp
new_l = [{field: d[field] for field in ['symbol', 'token_fundamentals']}
for d in l]
which is better equivalent of this:
new_l = []
for d in l:
new_d = {}
for field in ['symbol', 'token_fundamentals']:
new_d[field] = d[field]
new_l.append(new_d)
Judging by what your writing into d you want to save a list of objects so this would work:
[{"symbol": i['symbol'], "token_fundamentals": i['token_fundamentals']} for i in d]
Result:
[{'symbol': 'btc', 'token_fundamentals': 100}, {'symbol': 'eth', 'token_fundamentals': 97}]
I am new with the concept of dictionaries and trying to learn them. What I have is a dictionary like this:
{'cars': [{'values': [1, 534],
{'values': [25,32,164]
'bikes': [{'values': [23,12,1]
{'values': [2,4]
{'values': [68,69]
{'values': [4,93]
What I try to achieve is add Ids to all inner values starting from 1
If you want the ID as part of the value group, like this:
{'cars': [{'values': [1, 534], 'sedan': 1, 'count': 2, 'ID': 1},
{'values': [25, 32, 164], 'sedan': 1, 'count': 10, 'ID': 2}],
'bikes': [{'values': [23, 12, 1], 'road': 0, 'count': 9},
...
You can do:
for i in range(len(try_dict['cars'])):
try_dict['cars'][i]['ID'] = i+1
If you want what Phydeaux suggests, you can do:
new_dict = {'cars': {}}
for i in range(len(try_dict['cars'])):
new_dict['cars'][i+1] = try_dict['cars'][i]
Which will give you:
{'cars': {1: {'values': [1, 534], 'sedan': 1, 'count': 2},
2: {'values': [25, 32, 164], 'sedan': 1, 'count': 10}}}
If you want not just cars but also bikes (and maybe trucks, trains, whatever...). Use:
new_dict = {}
for key in try_dict.keys():
new_dict[key] = {}
for i in range(len(try_dict[key])):
new_dict[key][i+1] = try_dict[key][i]
This will give you:
{'cars': {1: {'values': [1, 534], 'sedan': 1, 'count': 2},
2: {'values': [25, 32, 164], 'sedan': 1, 'count': 10}},
'bikes': {1: {'values': [23, 12, 1], 'road': 0, 'count': 9},
2: {'values': [2, 4], 'road': 1, 'count': 24},
3: {'values': [68, 69], 'sedan': 0, 'count': 28},
4: {'values': [4, 93], 'sedan': 0, 'count': 6}}}
You can do this using a simple function:
def idx(dict, key):
dict = dict
dict[key].insert(0, 0)
return dict
Full Code:
def idx(dict, key):
dict = dict
dict[key].insert(0, 0)
return dict
dict = {'cars': [{'values': [1, 534],
'sedan': 1,
'count': 2},
{'values': [25,32,164],
'sedan': 1,
'count': 10}],
'bikes': [{'values': [23,12,1],
'road': 0,
'count': 9},
{'values': [2,4],
'road': 1,
'count': 24},
{'values': [68,69],
'sedan': 0,
'count': 28},
{'values': [4,93],
'sedan': 0,
'count': 6}]}
dict = idx(dict, "cars")
print(dict["cars"][1])
Explanation:
Replace dictionary with a new edited dictionary:
dict = {key: [...,...,...]}
dict = idx(dict, key)
Function is using the .insert method to insert 0 for the value of the first index to the key provided.
Learn more about Python .insert() method at:
[
https://www.w3schools.com/python/ref_list_insert.asp
I have a task to get the average some data in each hour inside a week.
{'hour': 0, 'count': 70}
{'hour': 1, 'count': 92}
{'hour': 2, 'count': 94}
{'hour': 3, 'count': 88}
{'hour': 4, 'count': 68}
{'hour': 5, 'count': 69}
{'hour': 6, 'count': 70}
{'hour': 7, 'count': 82}
{'hour': 8, 'count': 91}
{'hour': 9, 'count': 67}
{'hour': 10, 'count': 92}
{'hour': 11, 'count': 100}
{'hour': 12, 'count': 92}
{'hour': 13, 'count': 55}
{'hour': 14, 'count': 61}
{'hour': 15, 'count': 47}
{'hour': 16, 'count': 36}
{'hour': 17, 'count': 19}
{'hour': 18, 'count': 11}
{'hour': 19, 'count': 6}
{'hour': 20, 'count': 3}
{'hour': 21, 'count': 9}
{'hour': 22, 'count': 27}
{'hour': 23, 'count': 47}
The data above is the result of this query
result = Device.objects.filter(station__in=stations, created_at__range=(start_date, end_date)) \
.extra({'hour': 'hour(created_at)'}) \
.values('hour').annotate(count=Count('id')).order_by('hour')
the result is queryed by 7 days range, what I want to do is get the average for each hour in 7 days, exampe the total of count in hour 0 is 70 then i need to average it from 7 days.
Any suggestion?
Probably you can try like this with F() expression:
from django.db.models import F, ExpressionWrapper, DecimalField
result = result.annotate(average=ExpressionWrapper(F('count')/7, output_field=DecimalField()))
I am trying to lowercase all the keys in a dictionary(s) that are within a list. I actually have a code that prints the lowercase output I want within a for loop. I'm using a dictionary comprehension to lowercase, but I'm not sure how to append the changed values to my list.
amdardict = [{'1031': 98, '1032': 1, '33007': 70, 'AIRCRAFT_FLIGHT_NUMBER': 'CNFNXQ', 'DAY': 5, 'HEIGHT_OR_ALTITUDE': 1490.0, 'HOUR': 0, 'LATITUDE': 39.71, 'LONGITUDE': -41.79, 'MINUTE': 0, 'MONTH': 10, 'PHASE_OF_AIRCRAFT_FLIGHT': 5, 'TEMPERATURE_DRY_BULB_TEMPERATURE': 289.0, 'WIND_DIRECTION': 219, 'WIND_SPEED': 3.0, 'YEAR': 2019}
{'12101': 248.75, '4006': 55, '7010': 6135, '8009': 3, 'aircraft_flight_number': '????????', 'aircraft_registration_number_or_other_identification': 'AU0155', 'aircraft_tail_number': '??????', 'day': 5, 'destination_airport': '???', 'hour': 0, 'latitude': -34.3166, 'longitude': 151.9333, 'minute': 8, 'month': 10, 'observation_sequence_number': 64, 'origination_airport': '???', 'wind_direction': 208, 'wind_speed': 23.0, 'year': 2019}
]
for d in amdardict: print(dict((k.lower(), v) for k, v in d.items()))
Why modify the original list? Can you create a new empty list and slightly modify your code to append to that new list instead of printing:
new_list = []
for d in amdardict:
new_list.append(dict((k.lower(), v) for k, v in d.items()))
To change the keys in-place, you can use the dict.pop method.
>>> # Copy the list in case we make a mistake
>>> import copy
>>> backup = copy.deepcopy(amdardict)
>>> for d in amdardict:
... # <ake a list of keys() because we can't loop over keys()
... # and change keys simultaneously
... for k in list(d.keys()):
... if not k.islower():
# pop removes the key from the dict and returns the value
... d[k.lower()] = d.pop(k)
...
>>> amdardict
[{'aircraft_flight_number': 'CNFNXQ', 'day': 5, 'height_or_altitude': 1490.0, 'temperature_dry_bulb_temperature': 289.0, 'wind_direction': 219, 'wind_speed': 3.0, 'year': 2019, 'hour': 0, 'latitude': 39.71, 'longitude': -41.79, 'minute': 0, 'month': 10, 'phase_of_aircraft_flight': 5, '1031': 98, '1032': 1, '33007': 70}, {'aircraft_flight_number': '????????', 'aircraft_registration_number_or_other_identification': 'AU0155', 'aircraft_tail_number': '??????', 'day': 5, 'destination_airport': '???', 'hour': 0, 'latitude': -34.3166, 'longitude': 151.9333, 'minute': 8, 'month': 10, 'observation_sequence_number': 64, 'origination_airport': '???', 'wind_direction': 208, 'wind_speed': 23.0, 'year': 2019, '12101': 248.75, '4006': 55, '7010': 6135, '8009': 3}]
I have a model as such
class Post(models.Model):
submission_time = models.DateTimeField()
user = models.ForeignKey(User)
and I would like to have a queryset where it returns the number of Posts a user has made per month.
I have tried using ExtractMonth as so :
user.post_set.annotate(month_sub=ExtractMonth('submission_time')).values('month_sub').annotate(count=Count('month_sub'))
But its giving me a QuerySet like this :
<QuerySet [{'month_sub': 5, 'count': 1}, {'month_sub': 6, 'count': 1}, {'month_sub': 6, 'count': 1}, {'month_sub': 6, 'count': 1}, {'month_sub': 6, 'count': 1}, {'month_sub': 6, 'count': 1}, {'month_sub': 6, 'count': 1}]>
Instead of one like this(Which i'd like to have) :
<QuerySet [{'month_sub': 5, 'count': 1}, {'month_sub': 6, 'count': 7}]>
Any Ideas on how to receive a queryset like so ?
You are quite close, the only thing you are missing is an .order_by('month_sub') (yeah, I know that sounds a bit strange). So you should write:
user.post_set.annotate(
month_sub=ExtractMonth('submission_time')
).values('month_sub').annotate(
count=Count('month_sub')
).order_by('month_sub')
This will result in query that looks like:
SELECT EXTRACT(MONTH FROM `post`.`submission_time`) AS `month_sub`,
COUNT(EXTRACT(MONTH FROM `post`.`submission_time`)) AS `count`
FROM `post`
WHERE `post`.`user_id` = 123
GROUP BY EXTRACT(MONTH FROM `post`.`submission_time`)
ORDER BY `month_sub` ASC
(where 123 should be replaced with the id of the user).
You can perhaps boost performance a tiny bit, by using Count('id'), although it is possible this has no (noticeable) impact:
user.post_set.annotate(
month_sub=ExtractMonth('submission_time')
).values('month_sub').annotate(
count=Count('id')
).order_by('month_sub')
If I run this on a sample database, I get:
<QuerySet [{'count': 273, 'month_sub': 1},
{'count': 172, 'month_sub': 2},
{'count': 565, 'month_sub': 3},
{'count': 59, 'month_sub': 4},
{'count': 452, 'month_sub': 5},
{'count': 550, 'month_sub': 6},
{'count': 622 'month_sub': 7},
{'count': 43, 'month_sub': 8},
{'count': 357, 'month_sub': 9},
{'count': 378, 'month_sub': 10},
{'count': 868, 'month_sub': 11},
{'count': 293, 'month_sub': 12}]>
(did some formatting to make it easier to inspect the result)