Table of dictionaries - python

I have a table of dicts looking like:
[{
'variant_id': 4126274,
'stock': [
{'stock_id': 6, 'quantity': 86},
{'stock_id': 4, 'quantity': 23},
{'stock_id': 3, 'quantity': 9}
]
}, ...]
My goal is to unzip every piece of stock to look like this:
[{'variant_id': 4126274, 'stock_id': 6, 'quantity':86}
{'variant_id': 4126274, 'stock_id': 4, 'quantity':23}
{'variant_id': 4126274, 'stock_id': 3, 'quantity':9}...]
Is there any fast and optimal way to do this?

You could do something like:
result = [{'variant_id': entry['variant_id'],
'stock_id': stock_entry['stock_id'],
'quantity': stock_entry['quantity']} for entry in table for stock_entry in entry['stock']]
This gives
[{'quantity': 86, 'stock_id': 6, 'variant_id': 4126274},
{'quantity': 23, 'stock_id': 4, 'variant_id': 4126274},
{'quantity': 9, 'stock_id': 3, 'variant_id': 4126274}]

Here are two approaches: one with nested for loops, and one with a list comprehension.
data = [{'variant_id': 4126274, 'stock': [{'stock_id': 6, 'quantity': 86}, {'stock_id': 4, 'quantity': 23}, {'stock_id': 3, 'quantity': 9}]}]
result = []
for entry in data:
for stock in entry['stock']:
result.append({'variant_id': entry['variant_id'], 'stock_id': stock['stock_id'], 'quantity': stock['quantity']})
print(result)
result_list_comprehension = [{'variant_id': entry['variant_id'], 'stock_id': stock['stock_id'], 'quantity': stock['quantity']} for entry in data for stock in entry['stock']]
print(result_list_comprehension)

Related

Get unique elements in an array and add the value if same element is found - django

<QuerySet
[{'product': 6, 'quantity': 1},
{'product': 6, 'quantity': 10},
{'product': 7, 'quantity': 2},
{'product': 9, 'quantity': 3}]
>
how to get unique elements only in the array and add the quantity if same product is found. In the above eg: there are two "product: 6", so the new QuerySet should be
<QuerySet
[{'product': 6, 'quantity': 11},
{'product': 7, 'quantity': 2},
{'product': 9, 'quantity': 3}]
>

Python Web Scrapping

I'm trying to write a code in Python that gets specific data from this site:
exchange data
The information i'm interested in, is in the table at the middle of the page and I want to get the Price for each Q in the corresponding row. For example Q=0 price=18.9, Q=1 price = 19, etc.
Any suggestions how that can be done?
You can get the desired data from API. Because data is loaded dynamically by JS via API.
import requests
api_url='https://simcotools.app/api/resource/18'
req=requests.get(api_url).json()
data=[]
for item in req['qualities']:
Quantity = item['quality']
Price = item['price']
data.append({
'Quantity':Quantity,
'Price': Price
})
print(data)
Output:
[{'Quantity': 0, 'Price': 18.8}, {'Quantity': 1, 'Price': 19.0}, {'Quantity': 2, 'Price': 19.1}, {'Quantity': 3, 'Price': 19.2}, {'Quantity': 4, 'Price': 19.3}, {'Quantity': 5, 'Price': 20.75}, {'Quantity': 6, 'Price': 23.5}, {'Quantity': 7, 'Price': 23.5}, {'Quantity': 8, 'Price': 39.0}, {'Quantity': 9, 'Price': 50.0}, {'Quantity': 10, 'Price': 100.0}]

Repeating values when we use append function in list or update in dict

when I try to append a Dictonary values to a list I'm getting the value appended multiple time but when I try to see what is really happening in there by using print statement, the values are iterating properly but while appending it is appending same value multiple times
Here is my code
from random import randint
x = {'1':
{
'item_id': 6,
'item_name': 'burger',
'item_price': 10,
'item_quantity': 2
},
'2':
{
'item_id': 7,
'item_name': 'pizza',
'item_price': 15,
'item_quantity': 4
},
'3':
{
'item_id': 8,
'item_name': 'Biryani',
'item_price': 20,
'item_quantity': 6
}
}
cart=[]
items = {}
for y in x.values():
items['name'] = y['item_name']
items['price'] = y['item_price']
items['quantity'] = y['item_quantity']
print(items)
cart.append(items)
print(cart)
And This is the Output:
{'name': 'burger', 'price': 10, 'quantity': 2}
{'name': 'pizza', 'price': 15, 'quantity': 4}
{'name': 'Biryani', 'price': 20, 'quantity': 6}
[{'name': 'Biryani', 'price': 20, 'quantity': 6}, {'name': 'Biryani', 'price': 20, 'quantity': 6}, {'name': 'Biryani', 'price': 20, 'quantity': 6}]
>
You are mutating and appending the same dict items to cart again and again. Instantiate a new dict items = {} in each iteration of the for loop.
try initializing your dictionary every time inside the loop
cart=[]
for y in x.values():
items = {}
items['name'] = y['item_name']
items['price'] = y['item_price']
items['quantity'] = y['item_quantity']
print(items)
cart.append(items)
print(cart)

Combining multiple lists of dictionaries

I have several lists of dictionaries, where each dictionary contains a unique id value that is common among all lists. I'd like to combine them into a single list of dicts, where each dict is joined on that id value.
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
desired_output = [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
I tried doing something like the answer found at https://stackoverflow.com/a/42018660/7564393, but I'm getting very confused since I have more than 2 lists. Should I try using a defaultdict approach? More importantly, I am NOT always going to know the other values, only that the id value is present in all dicts.
You can use itertools.groupby():
from itertools import groupby
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
desired_output = []
for _, values in groupby(sorted([*list1, *list2, *list3], key=lambda x: x['id']), key=lambda x: x['id']):
temp = {}
for d in values:
temp.update(d)
desired_output.append(temp)
Result:
[{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
# combine all lists
d = {} # id -> dict
for l in [list1, list2, list3]:
for list_d in l:
if 'id' not in list_d: continue
id = list_d['id']
if id not in d:
d[id] = list_d
else:
d[id].update(list_d)
# dicts with same id are grouped together since id is used as key
res = [v for v in d.values()]
print(res)
You can first build a dict of dicts, then turn it into a list:
from itertools import chain
from collections import defaultdict
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
dict_out = defaultdict(dict)
for d in chain(list1, list2, list3):
dict_out[d['id']].update(d)
out = list(dict_out.values())
print(out)
# [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
itertools.chain allows you to iterate on all the dicts contained in the 3 lists. We build a dict dict_out having the id as key, and the corresponding dict being built as value. This way, we can easily update the already built part with the small dict of our current iteration.
Here, I have presented a functional approach without using itertools (which is excellent in rapid development work).
This solution will work for any number of lists as the function takes variable number of arguments and also let user to specify the type of return output (list/dict).
By default it returns list as you want that otherwise it returns dictionary in case if you pass as_list = False.
I preferred dictionary to solve this because its fast and search complexity is also less.
Just have a look at the below get_packed_list() function.
get_packed_list()
def get_packed_list(*dicts_lists, as_list=True):
output = {}
for dicts_list in dicts_lists:
for dictionary in dicts_list:
_id = dictionary.pop("id") # id() is in-built function so preferred _id
if _id not in output:
# Create new id
output[_id] = {"id": _id}
for key in dictionary:
output[_id][key] = dictionary[key]
dictionary["id"] = _id # push back the 'id' after work (call by reference mechanism)
if as_list:
return [output[key] for key in output]
return output # dictionary
Test
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
output = get_packed_list(list1, list2, list3)
print(output)
# [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
output = get_packed_list(list1, list2, list3, as_list=False)
print(output)
# {1: {'id': 1, 'value': 20, 'sum': 10, 'total': 30}, 2: {'id': 2, 'value': 21, 'sum': 11, 'total': 32}}
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
print(list1+list2+list3)
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
result = []
for i in range(0,len(list1)):
final_dict = dict(list(list1[i].items()) + list(list2[i].items()) + list(list3[i].items()))
result.append(final_dict)
print(result)
output : [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]

Ordering a Django queryset based on other list with ids and scores

I'm a bit mentally stuck at something, that seems really simple at first glance.
I'm grabbing a list of ids to be selected and scores to sort them based on.
My current solution is the following:
ids = [1, 2, 3, 4, 5]
items = Item.objects.filter(pk__in=ids)
Now I need to add a score based ordering somehow so I'll build the following list:
scores = [
{'id': 1, 'score': 15},
{'id': 2, 'score': 7},
{'id': 3, 'score': 17},
{'id': 4, 'score': 11},
{'id': 5, 'score': 9},
]
ids = [score['id'] for score in scores]
items = Item.objects.filter(pk__in=ids)
So far so good - but how do I actually add the scores as some sort of aggregate and sort the queryset based on them?
Sort the scores list, and fetch the queryset using in_bulk().
scores = [
{'id': 1, 'score': 15},
{'id': 2, 'score': 7},
{'id': 3, 'score': 17},
{'id': 4, 'score': 11},
{'id': 5, 'score': 9},
]
sorted_scores = sorted(scores) # use reverse=True for descending order
ids = [score['id'] for score in scores]
items = Item.objects.in_bulk(ids)
Then generate a list of the items in the order you want:
items_in_order = [items[x] for x in ids]

Categories