dict comprehension with list as value - python-3.x

I have a program that prompts the user for three pieces of input:
Student No.
Name
Age
I then populate a list with this info. This currently works fine.
I was wanting to change the list construct to a dictionary that has the Student No. as the key and a list with the Name and Age as values. I also want the list in case I decide to enlarge the number of inputs in the future.
I was wondering if I could use a dict comprehension but I can't find any examples of using a dict comp being used to create a dict with a list as the value.
The resulting dictionary would look like:
st_dict = {101: [Mark, 54],
102: [Bob, 49]
}
Is it possible, using a dict comp, to create this structure?
Basically I am wanting to do this:
st_dict = {Student_no: [Name, Age] per student entered}

Related

How to check if input is a key in dictionary even partially?

Lets say you have a dictionary that has a grocery item (key) and its price(value). We ask the user for input (grocery item) and they type in whatever. They dont know what item is in the dictionary or not. Im trying to specify that even if the input contains 1 word of the item in the dictionary, to use that as the key and get the price.
So if the official key in the dictionary was "Milk Gallon", and the user types in "milk", how can i make them reference the same thing? If they type milk i want the output to be the value of "Milk gallon"?
you can use if in
you can try this:-
store = {"milk gallon":100,"tomato":50,"fish":190}
user = input("Whatever you want-->")
for i in store:
if user.lower() in i:
user = i
print(user)

Adding a dictionary inside a dictionary

I have a dictionary which looks like this:
store = {}
And I have a bunch of data in another dictionary that looks like this:
items = {"hardware_items":23, "fruit_items":5, "fish_items": 23}
How can I put the items dictionary inside the store dict so I can achieve the following result?
store = {"hardware_items":23, "fruit_items":5, "fish_items": 23}
Thank you
Use the update method:
store.update(items)
This will add everything in items to store; beware though that if store already has existing keys with those names they will be overwritten.
If store dict is empty you can use the copy() method :
store = items.copy()
You can use store = items but it works as a reference (then modifying store will modify items)
Else, you can use a for loop :
for keys in items:
store[keys] = items[keys]
It will overwrite value if a key is already declared.
The output you want would appear to be a copy of the "items" dictionary in "store". You can do this, basically, in two ways.
1. Simple copy
You can write
store = items
and the output will be what you asked for.
Changing one of the two dictionaries, however, will also change the other.
2. Deep Copy
One of the ways to do a deep copy is:
store=copy.deepcopy(items)
In this case you will have two dictionaries with the same content, but they will be independent and you can edit them separately. Let me show an example:
import copy
store = {}
items = {"hardware_items":23, "fruit_items":5, "fish_items": 23}
#Print
print("Before operations")
print("ITEMS> "+str(items))
print("STORE> "+str(store))
store=copy.deepcopy(items)
#Print
print("After deep copy")
print("ITEMS> "+str(items))
print("STORE> "+str(store))
items["hardware_items"]=3
#Print
print("let's modify the first key value")
print("ITEMS> "+str(items))
print("STORE> "+str(store))
Your output will be:

What is the Python equivalent of a jagged array?

After years of using Excel and learning VBA, I am now trying to learn Python. Here's the scenario:
I asked 7 summer camp counselors which activities they would like to be in charge of. Each student had a random number of responses, and there is no upper limit on the number of activities chosen. However, each activity is unique, and once "claimed" by a student it cannot claimed by any other counselor. The results were:
Adam: archery, canoeing
Bob: frisbee, golf, painting, trampoline
Carol: tennis, dance, skating
Denise: cycling
Eddie: horseback, fencing, soccer
Fiona: painting
George: basketball, football
I'm most familiar with VB (I am an old guy) and in the past I would have stored the above info in a jagged array. But since I'm new to Python, I am confused as to how to do this. I think a list of lists would work for me and here is my code. Let's say I have a list of counselors, and separate lists for each counselors' activities. How do I merge them or put them in one data structure? What am I doing wrong below? Thank you.
counselors = []
counselors = ['Adam','Bob','Carol','Denise','Eddie','Fiona','George']
#create a list of Carol's activities
activities = []
activities = ['tennis','dance','skating']
counselors[2].append[(activities)]
A jagged array in Python is pretty much a list of lists as you mentioned.
I would use a dictionary to store the counselors activity information, where the key is the name of the counselor, and the value is the list of activities the counselor will be in charge of e.g.
counselors_activities = {"Adam": ["archery", "canoeing"],
"Bob": ["frisbee", "golf", "painting", "trampoline"],
"Carol": ["tennis", "dance", "skating"],
"Denise": ["cycling"],
"Eddie": ["horseback", "fencing", "soccer"],
"Fiona": ["painting"],
"George": ["basketball", "football"]}
And access each counselor in the dictionary as such:
counselors_activites["Adam"] # when printed will display the result => ['archery', 'canoeing']
In regards to the question, I would store the list of activities available in a list, and anytime an activity is chosen, remove it from the list and add it to the counselor in the dictionary as such:
list_of_available_activities.remove("archery")
counselors_activities["Adam"].append("archery")
And if a counselor no longer was in charge of the activity, remove it from them and add it back to the list of available activities.
Update: I have provided a more fully fledged solution below based on your requirements from your comments.
Text file, activites.txt:
Adam: archery, canoeing
Bob: frisbee, golf, painting, trampoline
Carol: tennis, dance, skating
Denise: cycling
Eddie: horseback, fencing, soccer
Fiona: painting
George: basketball, football
Code:
#Set of activities available for counselors to choose from
set_of_activities = {"archery",
"canoeing",
"frisbee",
"golf",
"painting",
"trampoline",
"tennis",
"dance",
"skating",
"cycling",
"horseback",
"fencing",
"soccer",
"painting",
"basketball",
"football"}
with open('activities.txt', 'r') as f:
for line in f:
# Iterate over the file and pull out the counselor's names
# and insert their activities into a list
counselor_and_activities = line.split(':')
counselor = counselor_and_activities[0]
activities = counselor_and_activities[1].strip().split(', ')
# Iterate over the list of activities chosen by the counselor and
# see if that activity is free to choose from and if the activity
# is free to choose, remove it from the set of available activities
# and if it is not free remove it from the counselor's activity list
for activity in activities:
if activity in set_of_activities:
set_of_activities.remove(activity)
else:
activities.remove(activity)
# Insert the counselor and their chosen activities into the dictionary
counselors_activities[counselor] = activities
# print(counselors_activities)
I have made one assumption with this new example, which is that you will already have a set of activities that can be chosen from already available:
I made the text file the same format of the counselors and their activities listed in the question, but the logic can be applied to other methods of storage.
As a side note and a correction from my second example previously, I have used a set to represent the list of activities instead of a list in this example. This set will only be used to verify that no counselor will be in charge of an activity that has already been assigned to someone else; i.e., removing an activity from the set will be faster than removing an activity from the list in worst case.
The counselors can be inserted into the dictionary from the notepad file without having to insert them into a list.
When the dictionary is printed it will yield the result:
{"Adam": ["archery", "canoeing"],
"Bob": ["frisbee", "golf", "painting", "trampoline"],
"Carol": ["tennis", "dance", "skating"],
"Denise": ["cycling"],
"Eddie": ["horseback", "fencing", "soccer"],
"Fiona": [], # Empty activity list as the painting activity was already chosen by Bob
"George": ["basketball", "football"]}

How to efficiently use Django query and Q to filter each object in a queryset and return 1 field value for each unique field in the queryset

I have query that returns the following queryset:
results = <QuerySet [<Product: ItemA>, <Product: ItemA>, <Product: ItemB>, <Product: ItemB>, <Product: ItemB>, <Product: ItemC>, <Product: ItemC>]>
The __str__ representation of the model is name and each Product variation likely has a different value for the price field. After this query, I need to search my database for each Product in the queryset and return the lowest price for each unique name so like:
Lowest price for all in database where name is == to ItemA
Lowest price for all in database where name is == to ItemB
Lowest price for all in database where name is == to ItemC
I use the following block of code to accomplish this goal:
query_list = []
for each in results:
if each.name not in query_list: #Checks if the name of the object is not in in the query list
query_list.append(each.name) #Adds just the name of the objects so there is just one of each name in query_list
for each in query_list:
priced = results.filter(name=each).order_by('price').first() #Lowest price for each name in query_list
This feel very inefficient. Is there a way to make a similar computation without having to append the unique name of each Product to a separate list, and iterating over that list, and then making a query for each one? I feel like there is a way to use a type of complex lookup to accomplish my goals, maybe event use less Python, and make the db do more of the work, but the above is the best I've been able to figure out so far. There can be a lot of different hits in results so I need this block to be as efficient as possible
It is easy after reading docs Generating aggregates for each item in a QuerySet and also "Interaction with default ordering or order_by()".
from django.db.models import Min
prices = {x['name']: x['lowest_price']
for x in results.values('name').annotate(lowest_price=Min('price').order_by()}
for product in results:
if product.name in prices and product.price == prices[product.name]:
priced = row # output the row
del prices[product.name]
That runs by two database queries.
An even more efficient solution with one query is probably possible with Window function, but it requires an advanced database backend and it can't work e.g. in tests with sqlite3.

How to get many to many values and store in an array or list in python +django

Ok
i have this class in my model :
i want to get the agencys value which is a many to many on this class and store them in a list or array . Agency which store agency_id with the id of my class on a seprate table.
Agency has it's own tabel as well
class GPSpecial(BaseModel):
hotel = models.ForeignKey('Hotel')
rooms = models.ManyToManyField('Room')
agencys = models.ManyToManyField('Agency')
You can make it a bit more compact by using the flat=True parameter:
agencys_spe = list(GPSpecial.objects.values_list('agencys', flat=True))
The list(..) part is not necessary: without it, you have a QuerySet that contains the ids, and the query is postponed. By using list(..) we force the data into a list (and the query is executed).
It is possible that multiple GPSpecial objects have a common Agency, in that case it will be repeated. We can use the .distinct() function to prevent that:
agencys_spe = list(GPSpecial.objects.values_list('agencys', flat=True).distinct())
If you are however interested in the Agency objects, for example of GPSpecials that satisfy a certain predicate, you better query the Agency objects directly, like for example:
agencies = Agency.objects.filter(gpspecial__is_active=True).distinct()
will produce all Agency objects for which a GPSpecial object exists where is_active is set to True.
I think i found the answer to my question:
agencys_sp = GPSpecial.objects.filter(agencys=32,is_active=True).values_list('agencys')
agencys_spe = [i[0] for i in agencys_sp]

Resources