Sorting random element into dictionary? Python - python

I am trying to append a random choice into a dictionary, but my code doesn't seem to be working.
The file I am using (mood.txt):
happy, Jennifer Clause
happy, Jake Foster
sad, Jonathan Bower
mad, Penny
excited, Logan
awkward, Mason Tyme
my code:
def theFile():
moodFile = open("mood.txt")
theMood = moodFile.readlines()
moodFile.close()
return(theMood)
def makeTheDict(myFile):
moodDict = {}
for lines in myFile:
(mood, name) = lines.split(",")
moodDict[mood] = name.strip()
return(moodDict)
def randomMood(name, mood, moodDict):
if mood in moodDict:
randomMood = random.choice(mood)
moodDict[mood] = randomMood
moodDict.append(name, randomMood)
print(name, "has been put in the", randomMood, "group")
def main():
moodFile = theFile()
moodDict = makeTheDict(moodFile)
name = input("Choose a name: ")
newMood = input("Choose a mood: ")
randomMood(name, newMood, moodDict)
For example, I want to add a "Jamie Green" into a random group, and if it randomly chose "sad" then -
happy, Jennifer Clause
happy, Jake Foster
sad, Jonathan Bower
mad, Penny
excited, Logan
awkward, Mason Tyme
#sad, Jamie Green
How would I append this into the dictionary randomly?
Thank you!

It seems that you want to map strings to lists of strings, but instead of that you are mapping strings to strings.
Look at this line:
moodDict[mood] = name.strip()
Here you are mapping the string mood to the string name.strip(). If at this point, there was already a name mapped to the current mood, the old value would be replaced and lost. In your file sample, both Jennifer and Jake are happy. At the first iteration of the for loop you have:
moodDict["happy"] = "Jennifer Clause"
Then, at the second step, you have.
moodDict["happy"] = "Jake Foster"
Here "Jake Foster" replaces "Jennifer Clause". Since the moods can be repeated, what you probably want is something like this:
if mood in moodDict:
moonDict[mood].append(name.strip())
else:
moonDict[mood] = [name.strip()]
This way, for each mood key you have a list of name values.
Regarding the randomMood function, there are may things doesn't look good:
The if statement should be indented since is part of the function. This should throw an IndentationError, but I will assume it happened when you copied the code into StackOverflow.
Mood is a string, so what you are actually doing in random.choice(mood) is to choose a random character from that string, which doesn't make any sense. You probably want to choose from the list of moods, which would be something like this randomMood = random.choice(moodDict.keys()).
Because of what I explained in the previous point, the following line just replace the value under the mood key with a random character from the mood, which doesn't make sense.
Dictionaries don't have any method named append, this should throw an error too. You probably want to replace it with this: moonDict[randomMood].append(name)
Finally, I don't understand why you ask the user to input a mood when it is supposed to be chosen randomly.
It seems you are a bit confused about what a Python dictionary is and how it works. Remember that it map keys to values. In your code your keys are the moods and the values are the names, both represented as strings. The keys are unique. This means that if you assign a new value to an existing key, the old value mapped under that key gets lost. If you want to deal with multiple values under the same key you should map the key to a collection of values, like a list, instead of a single value.

Related

How to append values to a list in a dictionary while using a while loop?

vacation_poll = {}
name_prompt = "\nWhat is your name? "
vacation_spot_prompt = "\nWhere would you like to go on vacation? "
repeat_prompt = "\nWould you like to continue? (yes/no) "
active = True
while active:
name = input(name_prompt)
vacation_spot = input(vacation_spot_prompt)
vacation_poll[name] = [vacation_spot]
repeat = input(repeat_prompt)
if repeat == 'no':
active = False
for name, spots in vacation_poll.items():
print("\nThese are " + name.title() + "'s places of interest: ")
for spot in spots:
print("\t" + spot.title())
print(vacation_poll)
My goal is to append a new vacation spot in a list inside the dictionary vacation_poll when the same key shows up. So if Joe shows up again after I continue the loop, the new vacation spot should be added to Joe's list of vacation spots, but instead I get it overwritten. I've tried to append using a for loop, but that didn't work either. How could I fix it to append a new value to the list each time the loop is continued?
Have you thought about the schema you'd like to use for the dictionary? From your code, it looks like you're trying to do something like
vacation_poll = {
'Bob': ['Fiji', 'Florida', 'Japan'],
'Joe': ['Disney Land', 'Six Flags', 'Lego Land']
}
When I approach these sorts of problems, usually what I do is set an if statement to check if the key doesn't yet exist in the dictionary and if it doesn't, I initialize it with a list:
if name not in vacation_poll:
vacation_poll[name] = []
This lets me not worry about if the list didn't already exist later in my code and I could do something like
vacation_poll[name].append(vacation_spot)
because after I'd initialized the value associated with name to be a list, I can count on a list being there.
In your case, you might consider using a set instead of a list since it forces only unique values to be stored. This way, if the user enters the same value twice, it'll only record it once even after inserting it again the second time.
You need to use a form of appending to the list. You cannot however just use one of the following:
vacation_poll[name]+=[vacation_spot]
vacation_poll[name].append(vacation_spot)
Doing this will throw an error because when a person's first vacation spot is being added, there is no value indexed at their name in the dictionary. Instead the get(index, default) method is needed.
vacation_poll[name]=vacation_poll.get(name, [])+[vacation_spot]
This will be have as desired. When the key is not yet in the dictionary, get() will return the second parameter, the default value, which is an empty list in this case.

I have this very long piece of code that defines a list using x[0]=2 and so on in python 3.7. Why doesn't it work?

This is what my code is at the moment and I was wondering if I can assign list values like this.(I'm making a quote generator.)
import random as random
quotes = []
authors = []
quotes[0] = "I have a new philosophy. I'm only going to dread one day at a time."
authors[0] = "Charles Schulz"
quotes[1] = "Reality is the leading cause of stress for those in touch with it."
...
authors[5577] = "Henry David Thoreau"
quotes[5578] = "Sometimes the cards we are dealt are not always fair. However you must keep smiling and moving on."
authors[5578] = "Tom Jackson"
x=random.randint(2,5577)
for y in range(0,5579,1):
print(quotes[y]+" "+author[y])```
You are getting index out of range error since you are trying to access elements from an empty array. You can either initialize the author and quotes list:
authors = [None] * 5579
quotes = [None] * 5579
or a better way to add elements to list would be using the append method.
authors = []
quotes = []
quotes.append("I have a new philosophy. I'm only going to dread one day at a time.")
authors.append("Charles Schulz")
...
quotes.append("Sometimes the cards we are dealt are not always fair. However you must keep smiling and moving on.")
authors.append("Tom Jackson")
for author, quote in zip(authors,quotes):
print("{} {}".format(author, quote))
As stated in the comments, if you create an empty list, you can't assign values with the [] operator, that's for referencing elements that already exist inside the list (so you can update or read them). For adding new values to an empty list we use the append method like this:
quotes = []
quotes.append("I have a new philosophy. I'm only going to dread one day at a time.")
print(quotes[0])
>>> "I have a new philosophy. I'm only going to dread one day at a time."
You can now modify it because it exists:
quotes[0] = "Reality is the leading cause of stress for those in touch with it."
print(quotes[0])
>>> "Reality is the leading cause of stress for those in touch with it."
If you try to access index 1 it will give you an IndexError because it only has index 0 (in my example).
From more on lists, the append() function suggests a roundabout alternative to what you're trying to do:
>>> quotes = []
>>> quotes[0:] = ["first quote"]
>>> quotes[1:] = ["second quote"]
>>> quotes
['first quote', 'second quote']
This requires that both left hand and right hand sides be lists, and makes sure that you can't access lists that haven't had anything assigned to them yet.
As I mentioned in the comment above, IndexError comes from the list not having that element, which prevents one from mistakenly doing something like quotes[55] and expecting it to work too early on.
You are doing quotes[0] and so on, while quotes being empty, does not contain an index 0, 1, etc. You should use append() function instead, to add elements to your list.
Or, if you really want to use quotes[0] and so on, then do
quotes = [None] * 5579
or
quotes = [''] * 5579
at the start of the program.

Printing a Table from a Dictionary [duplicate]

This question already has answers here:
Dictionary Help! Extracting values and making a table
(2 answers)
Closed 8 years ago.
Here's the question that I'm supposed to code for:
Write the contract, docstring and implementation for a function showCast that takes a movie title and prints out the characters with corresponding actors/actresses from the given movie in an alphabetical order of characters. The columns must be aligned (20 characters (including the character's name) before the name of the actor/actress.) If the movie is not found, it prints out an error message.
It gives an example of what's supposed to happen here
>>> showCast("Harry Potter and the Sorcerer's Stone")
Character Actor/Actress
----------------------------------------
Albus Dumbledore Richard Harris
Harry Potter Daniel Radcliffe
Hermione Granger Emma Watson
Ron Weasley Rupert Grint
>>> showCast('Hairy Potter')
No such movie found
Here are other functions that I've written for the same project that will probably be of assistance in answering the question. A summary of what I've had to do so far is that I'm creating a dictionary, called myIMDb, with a key of the title of the movie, and the value another dictionary. In that dictionary that key is a character of a movie, and the value is the actor. And I've done stuff with it. myIMDb is a global variable for the record.
Other functions, what they do is the docString
def addMovie (title, charList, actList):
"""The function addMovie takes a title of the movie, a list of characters,
and a list of actors. (The order of characters and actors match one
another.) The function addMovie adds a pair to myIMDb. The key is the title
of the movie while the value is a dictionary that matches characters to
actors"""
dict2 = {}
for i in range (0, len(charList)):
dict2 [charList[i]] = actList[i]
myIMDb[title] = dict2
return myIMDb
I've added three movies,
addMovie("Shutter Island", ["Teddy Daniels", "Chuck Aule"],["Leonardo DiCaprio, ","Mark Ruffalo"])
addMovie("Zombieland", ["Columbus", "Wichita"],["Jesse Eisenberg, ","Emma Stone"])
addMovie("O Brother, Where Art Thou", ["Everett McGill", "Pete Hogwallop"],["George Clooney, ","John Turturro"])
def listMovies():
"""returns a list of titles of all the movies in the global variable myIMDb"""
return (list(myIMDb.keys()))
def findActor(title, name):
""" takes a movie title and a character's name and returns the
actor/actress that played the given character in the given movie. If the
given movie or the given character is notfound, it prints out an error
message"""
if title in myIMDb:
if name in myIMDb[title]:
return myIMDb[title][name]
else:
return "Error: Character not in Movie"
else:
return "Error: No movie found"
Now where I'm having trouble
I'm supposed to write the showCast function, but I'm having a lot of trouble. I've been tinkering with it for a while but when I call myIMDb.values() everything returns. And I can't seem to loop through it to sort them to create the table.
Here's what I've come up with so far, but it doesn't do what I was hoping. I'm just hoping that one of you can steer me in the right direction. (The commented out region is what I was doing before, just so you can see my train of thought. [the print(alist) and print(alist[0]) was just to confirm that it's one big entry in a list, not separated at all])
def showCast(title):
if title in myIMDb:
actList=[]
chList=[]
aList = list(myIMDb.values())
print (aList)
print (aList[0])
""""for i in range (len(aList)):
if i%2==0:
chList.append(aList[i])
else:
actList.append(aList[i])
print(chList)
print(actList)""""
else:
return "Movie not Found"
It's an old question, but I'll take a stab. I think your confusion comes from the nested nature of the myIMDb object. To get back information about a specific movies, you should use the title as a key to myIMDb, e.g. myIMDb[title]. What you get back is another dictionary, that you can then use to get the character/actor key value pairs.
Here's a working version of the showCast function:
def showCast(title):
if title in myIMDb:
print("{0:20} {1:20}".format("Character", r"Actor/Actress"))
print("-"*40)
for character, actor in myIMDb[title].items():
print("{0:20} {1:20}".format(character, actor))
else:
return "Movie not Found"
The first print statement generates the heading, and uses the Python's format string method to get the aligned spacing that you want. The next print statement is the divider, and then the meat of the function is simply iterating over the pairs with a for loop.
I hope that helps.

Alphabetize a List of Multiline Values in Python?

I have a list of names and addresses organized in the following format:
Mr and Mrs Jane Doe
Candycane Lane
Magic Meadows, SC
I have several blocks of data written like this, and I want to be able to alphabetize each block by the last name (Doe, in this case). After doing some digging, the best I can reckon is that I need to make a "List of lists" and then use the last name as a key by which to alphabetize the block. However, given by freshness to python and lack of Google skills, the closest I could find was this. I'm confused as to converting each block to a list and then slicing it; I can't seem to find a way to do this and still be able to alphabetize properly. Any and all guidance is greatly appreciated.
If I understood correctly, what you want basically is to sort values by "some computation done on the value", in this case the extracted last name.
For that, use the key keyword argument to .sort() or sorted():
def my_key_function(original_name):
## do something to extract the last name, for example:
try:
return original_name.split(',')[1].strip()
except IndexError:
return original_name
my_sorted_values = sorted(my_original_values, key=my_key_function)
The only requirement is that your "key" function is deterministic, i.e. always return the same output for each given input.
You might also want to sort by last name and then first name: in this case, just return a tuple (last, first): if last si the same for two given items, first will be used to further sort the two.
Update
For your specific case, this function should do the trick:
def my_key_function(original_name):
return original_name.splitlines()[0].split()[-1]
Assuming you already have the data in a list
l = ['Mr and Mrs Jane Smith\nCandycane Lane\nMagic Meadows, SC',
'Mr and Mrs Jane Doe\nCandycane Lane\nMagic Meadows, SC',
'Mr and Mrs Jane Atkins\nCandycane Lane\nMagic Meadows, SC']
You can specify the key to sort on.
l.sort(key=lambda x: x.split('\n')[0].split(' ')[-1])
In this case, get the last word (.split(' ')[-1]) on the first line (.split('\n')[0])
you want to make a new list where each entry is a tuple containing the sort key you want and the whole thing. Sort that list and then get the second component of each entry in the sort:
def get_sort_name (address):
name, address, city = address.split('\n')
return (name.split(' ')[-1] , address) # last item of first line & whole thing as tulle
keyed_list = map (get_sort_name, addresses)
keyed_list.sort()
sorted_addresses = [item[1] for item in keyed_list]
Thi could be more compact using lambdas of course but its better to be readable :)

Group related objects in Django

I'm building an app where you can search for objects in a database (let's assume the objects you search for are persons). What I want to do is to group related objects, for example married couples. In other words, if two people share the same last name, we assume that they are married (not a great example, but you get the idea). The last name is the only thing that identifies two people as married.
In the search results I want to display the married couples next to each other, and all the other persons by themselves.
Let's say you search for "John", this is what I want:
John Smith - Jane Smith
John Adams - Nancy Adams
John Washington
John Andersson
John Ryan
Each name is then a link to that person's profile page.
What I have right now is a function that finds all pairs, and returns a list of tuples, where each tuple is a pair. The problem is that on the search results, every name that is in a pair is listed twice.
I do a query for the search query (Person.objects.filter(name__contains="John")), and the result of that query is sent to the match function. I then send both the original queryset and the match function result to the template.
I guess I could just exclude every person that the match function finds a match for, but I don't know, but is that the most efficient solution?
Edit:
As I wrote in a comment, the actual strings that I want to match are not identical. To quote myself:
In fact, the strings I want to match are not identical, instead they
look more like this: "foo2(bar13)" - "foo2(bar14)". That is, if two
strings have the same foo id (2), and if the bar id is an odd number
(13), then its match is the bar id + 1 (14). I have a regular
expression to find these matches
First get your objects sorted by last name:
def keyfun(p):
return p.name.split()[-1]
persons = sorted(Person.objects.all(), key = keyfun)
Then use groupby:
from itertools import groupby
for lname, persons in groupby(persons, keyfun):
print ' - '.join(p.name for p in persons)
Update Yes, this solution works for your new requirement too. All you need is a stable way to generate keys for each item, and replace the body of the keyfun with it:
from re import findall
def keyfun(p):
v1, v2 = findall(p.name, '\d+')
tot = int(v1) + int(v2) % 2
return tot
Your description for how to generate the key for each item is not clear enough, although you should be able to figure it out yourself with the above example.

Categories

Resources