How to create a nested dictionary from multiple list? - python

How do I combine three separate list into one single dictionary?
Currently I have three operator inputs, where each input is split into a list.
item_input = input("Enter products seperated by space")
price_input = input("Enter price seperated by space")
stock_input = input("Enter stock seperated by space")
items = item_input.split()
price = price_input.split()
stock = stock_input.split()
I assume my first step would be to combine the price_input and stock_input into one dictionary first, and then nest them into the products_input.
I've tried using the fromkey method to make the price_input in its own dictionary to start with but the keys and values are in the opposite positions that I want
Example code:
price = [1,2,3]
price_dict = dict.fromkeys (price, "price")
#Output = {1: 'price', 2: 'price', 3: 'price'}
#Inteded output = {"price": 1, "price": 2, "price": 3}
This is the intended final output that I need.
products = {
"apple": {"price": 3.5, "stock": 134},
"banana": {"price": 6.82, "stock": 52},
"cake": {"price": 23, "stock": 5}
}

You could do this with a dictionary comprehension:
answer={x[0]: {"price": x[1], "stock" : x[2]} for x in zip(items, price, stock)}
This is similar to a list comprehension but returns a dictionary.
zip(items, price, stock) turns the three lists into a single list of tuples. Actually it is probably an generator - but here the effect here is the same.
Then it just iterate over this joined List/generator and construct each entry of the final dictionary.

You can zip item, price and stock together and then just use a dictionary comprehension:
items = input("Items: ").split()
prices = map(float, input("Prices: ").split())
stocks = map(int, input("Stocks: ").split())
products = {
item: {"price": price, "stock": stock}
for item, price, stock in zip(items, prices, stocks)
}
However, it might be better if the user could enter items one by one instead of having to add all at once so you could use a loop for that, the user inputs values separated by comma and to exit just doesn't type anything, simply pressers enter key.
products = {}
new_product = input("Item, price, stock: ")
while new_product:
item, price, stock = new_product.split(",")
products[item.strip()] = {"price": float(price), "stock": int(stock)}
new_product = input("Item, price, stock: ")

Related

Iterate through nested dictionary values and return an ordered list based on dict's values

I have a nested dictionary titled 'transportation_costs' that contains the transportation costs associated with every facility-customer combination. I need to iterate through each customer (key2) in the dictionary and generate five ordered lists (one for each customer) that contains the facilities ranked from cheapest to most expensive for a given customer based on the value in the nested dictionary.
*** When I say "cheapest", I mean it has a lower transportation cost.
transportation_cost=
{'Fac-1' : {"Apple":4,"Samsung":5,"Huawei":6,"Nokia":8,"Motorolla":10},
'Fac-2' : {"Apple":6,"Samsung":4,"Huawei":3,"Nokia":5,"Motorolla":8},
'Fac-3' : {"Apple":9,"Samsung":7,"Huawei":4,"Nokia":3,"Motorolla":4},
'Fac-4' : {"Apple":3,"Samsung":4,"Huawei":8,"Nokia":4,"Motorolla":4},
'Fac-5' : {"Apple":4,"Samsung":7,"Huawei":5,"Nokia":3,"Motorolla":2}}
I need the final ouput to be something like this:
"Apple" = ['FAC-4', 'FAC-5', 'FAC-3', 'FAC-2','FAC-1']
"Samsung" = ['FAC-2', 'FAC-4', 'FAC-3', 'FAC-5','Fac-1']
"Huawei"= ['FAC-3', 'FAC-5', 'FAC-1', 'FAC-4','FAC-2']
"Nokia" = ['FAC-5', 'FAC-3', 'FAC-2', 'FAC-4','FAC-1']
"Motorolla" = ['FAC-5', 'FAC-1', 'FAC-3', 'FAC-2', 'FAC-4']
Try:
all_keys = set(k for v in transportation_cost.values() for k in v.keys())
out = {
k: [
*sorted(
transportation_cost.keys(), key=lambda x: transportation_cost[x][k]
)
]
for k in all_keys
}
print(out)
Prints:
{
"Huawei": ["Fac-2", "Fac-3", "Fac-5", "Fac-1", "Fac-4"],
"Motorolla": ["Fac-5", "Fac-3", "Fac-4", "Fac-2", "Fac-1"],
"Apple": ["Fac-4", "Fac-1", "Fac-5", "Fac-2", "Fac-3"],
"Nokia": ["Fac-3", "Fac-5", "Fac-4", "Fac-2", "Fac-1"],
"Samsung": ["Fac-2", "Fac-4", "Fac-1", "Fac-3", "Fac-5"],
}

How To Append String To Dictionary in Python within Forloop

i need to append a value of string to a specific key in dictionary in python within forloop, and if the data in forloop is empty then give the value of empty string which i'm not able to get it right, here is some of the code,
top100 = {}
for product in product_list:
title = product.xpath('a[#class="someClass"]/text()') # LIST of 100
price = product.xpath('div[#class="someClass"]/text()') # LIST of 100
# the value in the title is list of 100 title
# more like ['title1', 'title2', ...] and so the price [100, 230, ...]
# how to append each pairs of title and price so i have list of dictionary
top100['title'].append(title)
top100['price'].append(price)
print( top100)
output:
KeyError: 'title'
but i need something more like:
top100 = [{'title': 'title1', 'price': 'price1'},
{'title': 'title2', 'price': 'price2'}
]
The top 100 variable should be a list, then append a dictionary
top100 = []
for product in product_list:
title = product.xpath('a[#class="someClass"]/text()') # LIST of 100
price = product.xpath('div[#class="someClass"]/text()') # LIST of 100
top100.append({'title':title,'price':price})
print( top100)
You need to make top100 a list with many nested dictionaries, with the following code:
top100 = []
for product in product_list:
title = product.xpath('a[#class="someClass"]/text()') # LIST of 100
price = product.xpath('div[#class="someClass"]/text()') # LIST of 100
top100.append({'title':title,'price':price})
Here for the another version of result
top100 = {'title':[],'price':[]}
for product in product_list:
title = product.xpath('a[#class="someClass"]/text()') # LIST of 100
price = product.xpath('div[#class="someClass"]/text()') # LIST of 100
top100['title'].append(title)
top100['price'].append(price)
print( top100)
This should output
{'title':[..., ..., ... ],'price':[..., ..., ...]}
thanks for the answer i was able to find my own solution,
top100 = []
for product in product_list:
titles = product.xpath('a[#class="someLink"]/text()')
prices = product.xpath('div[#class="somePrice"]/text()')
for title, price, in zip(titles, prices):
top100.append({'title':title, 'price':price})
output:
top100 = [{'title': 'title1', 'price': '100'},
{'title': 'title2', 'price': '200'}]

How to map value to a string in separate lists

I am creating a function which returns the product names in order of most revenue generated. I have managed to get the function to return the costs in the correct descending order, but I am having stuck in trying to mapthe prices to the products. Is this the right way to go about solving this?
products = ["Computer", "Cell Phones", "Vacuum Cleaner"]
amounts = [3,24,8]
prices = [199,299,399]
def top3(products, amounts, prices):
totals = []
items = []
for item, num1, num2 in zip(products, amounts, prices):
totals.append(num1 * num2)
items.append(item)
return sorted(totals, reverse = True)
Using the sorted() with dictionary
def top3(products, amounts, prices):
d = dict(zip(products, zip(amounts, prices)))
return sorted(d.keys(), key=lambda x: d[x][1] * d[x][0], reverse=True)
I like your approach. However, your code will not sort the product names. You can do this:
items = []
for item, num1, num2 in zip(products, amounts, prices):
totals.append((item, num1 * num2))
return sorted(totals, reverse = True)
Alternate solution using comprehensions:
items = [(item, num1 * num2) for item, num1, num2 in zip(products, amounts, prices)]
return sorted(totals, reverse = True)
but I am having stuck in trying to map the prices to the products
First, create data that includes both the product name and revenue, and then sort that. The built-in comparison for sequences (including tuples and lists) in Python compares them an element at a time (just as strings are compared a character at a time). So:
totals = sorted(
[
(amount * price, name)
for name, amount, price in zip(products, amounts, prices)
],
reverse=True
)
You can see that each item in the list will be a pair (2-tuple) of the revenue and name; you can do what you need with this information.
The named tuple from python's built-in collections is an overlooked tools that's handy for making code like this readable. You can create a lightweight type that gives you properties like object attributes, but with the storage requirements of a simple tuple.
For example, you can create a Sales tuple type with:
Sales = namedtuple('Sales', ('name', 'amount', 'price'))
s = Sales('A Product', 20, 30.99)
# Sales(name='A Product', amount=20, price=30.99)
s.name
# 'A Product'
You can solve your problem in a nicely readable way since you can refer to the properties by attribute:
from collections import namedtuple
Sales = namedtuple('Sales', ('name', 'amount', 'price'))
products = ["Computer", "Cell Phones", "Vacuum Cleaner"]
amounts = [3,24,8]
prices = [199,299,399]
sales = [Sales(*item) for item in zip(products, amounts, prices)]
# [Sales(name='Computer', amount=3, price=199),
# Sales(name='Cell Phones', amount=24, price=299),
# Sales(name='Vacuum Cleaner', amount=8, price=399)]
#get just the names sorted by amount * price
[s.name for s in sorted(sales, key=lambda s: s.price * s.amount, reverse=True)]
# ['Cell Phones', 'Vacuum Cleaner', 'Computer']
You can merge those three lists into one list containing the product name and the revenue. Then from there, you can sort the list by the product name using sorted(). With this, you can also sort the list by the revenue generated by changing lambda x : x[0] to lambda x : x[1]. This is also assuming that all lists have the same length and the prices/amounts are in the same order as products.
merged = [(products, amounts * price) for products, amounts, price in zip(products, amounts, price)]
total = sorted(merged, key = lambda x : x[0])
In one form or other, you will want to put the products and the items together into some kind of collection, then use the total as the key for sorting but return the name.
In every case, the key argument to sort contains a reference to a function which takes one of the elements being sorted and returns a key to use for determining the sort position of that element.
Example with list of 2-tuples. (item, total)
def top3(products, amounts, prices):
item_totals = []
for item, num1, num2 in zip(products, amounts, prices):
item_totals.append((item, num1 * num2))
item_totals.sort(key=lambda t: t[1], reverse=True)
return [t[0] for t in item_totals]
Here, the lambda t: t[1] is used to construct a function which takes the 2-tuple and returns the second item, i.e. the total. It is equivalent to defining a little function:
def get_sort_key(t):
return t[1]
and then passing the function:
item_totals.sort(key=get_sort_key, reverse=True)
Example with list of dictionaries
For better readability instead of using a list of 2-tuples, we could have a list of dictionaries with keys 'item' and 'total':
def top3(products, amounts, prices):
item_totals = []
for item, num1, num2 in zip(products, amounts, prices):
item_totals.append({'item': item, 'total': num1 * num2})
item_totals.sort(key=lambda t: t['total'], reverse=True)
return [t['item'] for t in item_totals]
In that case, a function that you could use instead of the lambda can be generated by using itemgetter from the operator package. You would use:
from operator import itemgetter
and the call to sort can then be changed to:
item_totals.sort(key=itemgetter('total'), reverse=True)
Example with single dictionary
We could also just put everything into one dictionary, with the product as the key and the total as the value. But in this case, it relies on the names not being duplicated.
def top3(products, amounts, prices):
item_totals = {}
for item, num1, num2 in zip(products, amounts, prices):
item_totals[item] = num1 * num2
return sorted(item_totals.keys(),
key=lambda item: item_totals[item],
reverse=True)
There are more compact ways to write all of these, which avoid the need for the explicit for loop when building the collection prior to sorting, as demonstrated by some of the other answers, but this is the general principle.
Here is what you can do to list each product in the order of their prices, from most expensive to cheapest:
products = ["Computer", "Cell Phones", "Vacuum Cleaner"]
amounts = [3,24,8]
prices = [199,299,399]
def top3(prd, amt, prc):
lst = sorted([(prc, prd) for prd, amt, prc in zip(products, amounts, prices)],reverse = True)
return [t[1] for t in lst]
print(top3(products, amounts, prices))
Output:
['Vacuum Cleaner', 'Cell Phones', 'Computer']
Here is what you can do to list each product in the order of how much was spent on them, most to least:
products = ["Computer", "Cell Phones", "Vacuum Cleaner"]
amounts = [3,24,8]
prices = [199,299,399]
def top3(prd, amt, prc):
lst = sorted([(prc*amt, prd) for prd, amt, prc in zip(products, amounts, prices)],reverse = True)
return [t[1] for t in lst]
print(top3(products, amounts, prices))
Output:
['Cell Phones', 'Vacuum Cleaner', 'Computer']

copy items from first list based on a value from second list in Python

I have following two lists.
marks = [120, 80, 150, 130, 140, 130, 220]
student = ["Joe", "Zoe", "Zoe", "Joe", "Zoe", "Joe", "Zoe"]
I want to extract items from list 1 based on item 'Joe' from list 2 and then take a mean of extracted values. How can I do that using loop or list comprehension.
For example, extract 120, 130, and 130 from the marks list given the student Joe.
You can zip the two lists together and store the scores for the students in a dict. Then if you want to average it, just find the count of the student in the students list.
scores = {}
for mark, student in zip(marks, students):
scores[student] = scores.get(student, 0) + mark
joe_average = scores['Joe'] / students.count('Joe')
If you just want the scores of a single student in a list, an easy comprehension would be
[mark for mark, student in zip(marks, students) if student == 'Joe']
You can get that average as follows:
joes_marks = [m for m, s in zip(marks, student) if s == 'Joe']
sum(joes_marks) // len(joes_marks)
# 126
This may help
from collections import defaultdict
# Create a dict with empty list as default value.
d = defaultdict(list)
# Initialise the list.
student = ["Joe", "Zoe", "Zoe", "Joe", "Zoe", "Joe", "Zoe"]
marks = [120, 80, 150, 130, 140, 130, 220]
# Iterate list with enumerate.
for idx, e in enumerate(student):
d[e].append(idx)
# Print out the occurrence of 'Joe'.
res = d['Joe']
sum_marks=0
for i in res :
sum_marks += marks[i]
# Prin the output expected
print sum_marks/len(res)

Python Dictionary - find average of value from other values

I have the following list
count = 3.5, price = 2500
count = 3, price = 400
count = 2, price = 3000
count = 3.5, price = 750
count = 2, price = 500
I want to find the average price for all where the count is the same. For example:
count = 2, price = 3000
count = 2, price = 500
3000 + 500 = 3500
3500/2 = 1750
Avg for 'count 2' is 1750
Here's my code so far
avg_list = [value["average"] for value in dictionary_database_list]
counter_obj = collections.Counter(count_list)
print ("AVG:")
for i in counter_obj:
print (i, counter_obj[i])
I'll admit I'm not 100% clear on what you're looking for here, but I'll give it a shot:
A good strategy when you want to iterate over a list of "things" and accumulate some kind of information about "the same kind of thing" is to use a hash table. In Python, we usually use a dict for algorithms that require a hash table.
To collect enough information to get the average price for each item in your list, we need:
a) the total number of items with a specific "count"
b) the total price of items with a specific "count"
So let's build a data structure that maps a "count" to a dict containing "total items" and "total price" for the item with that "count".
Let's take our input in the format:
item_list = [
{'count': 3.5, 'price': 2500},
{'count': 3, 'price': 400},
{'count': 2, 'price': 3000},
{'count': 3.5, 'price': 750},
{'count': 2, 'price': 500},
]
Now let's map the info about "total items" and "total price" in a dict called items_by_count:
for item in item_list:
count, price = item['count'], item['price']
items_by_count[count]['total_items'] += 1
items_by_count[count]['total_price'] += price
But wait! items_by_count[count] will throw a KeyError if count isn't already in the dict. This is a good use case for defaultdict. Let's define the default value of a count we've never seen before as 0 total price, and 0 total items:
from collections import defaultdict
items_by_count = defaultdict(lambda: {
'total_items': 0,
'total_price': 0
})
Now our code won't throw an exception every time we see a new value for count.
Finally, we need to actually take the average. Let's get the information we need in another dict, mapping count to average price. This is a good use case for a dict comprehension:
{count: item['total_price'] / item['total_items']
for count, item in items_by_count.iteritems()}
This iterates over the items_by_count dict and creates the new dict that we want.
Putting it all together:
from collections import defaultdict
def get_average_price(item_list):
items_by_count = defaultdict(lambda: {
'total_items': 0,
'total_price': 0
})
for item in item_list:
count, price = item['count'], item['price']
items_by_count[count]['total_items'] += 1
items_by_count[count]['total_price'] += price
return {count: item['total_price'] / item['total_items']
for count, item in items_by_count.iteritems()}
If we pass in our example input dict, this function returns:
{3.5: 1625, 2: 1750, 3: 400}
Which is hopefully the output you want! Be cautious of gotchas like float division in your particular Python version.
You need to iterate over your items
See documentation
avg(dictionary.values()) is probably what you want

Categories