appending to a list from inside a dictionary? - python

Attempting to add authors and their book titles to a list inside of a dictionary so that each author can support multiple book titles. In the code, I have 3 authors already and each has 1 book title, but they need to be able to support at least 1 more book title.
I have the values (book titles) of the keys (authors) nested inside of a list inside the dictionary already, but I don't know how to append more values to the existing keys that are inside of the existing list.
readings = {'George Orwell': ['1984'], 'Harper Lee': ['To Kill a Mockingbird'], 'Paul Tremblay': ['The Cabin at the End of the World']} # list inside of dict.
I need to use the following code to append the new book titles to the list
def add(readings): # appending to list will go here
author = input('\nEnter an author: ')
if author in readings: # check if input already inside dict.
bookTitle = readings[author]
print(f'{bookTitle} is already added for this author.\n')
else:
bookTitle = input('Enter book title: ')
bookTitle = bookTitle.title()
readings[author] = bookTitle
print(f'{bookTitle} was added.\n')
I expect that you are not able to add the same book title twice and not be able to add the same author twice either. I am expected to be able to input book titles for an existing author (or new author not already existing) while the program is running, then be able to view all of the authors and their book title(s) via a 'command menu' (not shown).

You're workflow is a little off. After checking for the author, then check for the book in the list of books by that author. You can add a title to the list of books using .append. Try this:
def add(readings): # appending to list will go here
author = input('\nEnter an author: ')
if author in readings: # check if input already inside dict.
books = readings[author]
print(f'Found {len(books)} books by {author}:')
for b in books:
print(f' - {b}')
else:
readings[author] = []
bookTitle = input('Enter book title: ')
bookTitle = bookTitle.title()
if bookTitle in readings[author]:
print(f'{bookTitle} is already added for this author.')
else:
readings[author].append(bookTitle)
print(f'Add "{bookTitle}"')

So you are trying to add multiple books to an author, is that correct? Since the values in your dictionary are already stored as list, you can try doing -
readings[author].append(bookTitle)
instead of
readings[author] = bookTitle

Related

How extract text from selected books, convert them to tags, and add them to metadata in CALIBRE?

I created a python code in VScode that allows me to perform text searches within an epub book, these searches consist of matching the text of the book with regular expressions. These regular expressions come from patterns that I formulated for the tags in my library. I have already managed to get over 400 tags this way and I have a custom column for them, I add the # symbol at the beginning to differentiate them from tags downloaded from other sources. I have 3000+ books and I want each of them to be attacked by these 400+ regular expressions.
I need help because my code only contemplates the search in a single book and what I want to configure is:
**Run the code on selected books from my library (books_ids).**
**Found tags are added to the metadata.**
**Add a verification tag confirming that the book was processed.**
Code:
import re
import ast
from epub_conversion.utils import open_book, convert_epub_to_lines
import colorama
colorama.init()
"test_dict.txt = {'#publication_(*history)': r'\bpublication\b[^.]*\bhistory',
'#horror_fiction': r'\bhorror fiction',
'#story_(*writer)': r'\bstory\b[^.]*\bwriter',
'#published_(*books)': r'\bpublished\b[^.]*\bbooks',
'#books_(*poems)': r'\bbook[^.]*\bpoem',
'#new_discovery': r'\bnew discovery',
'#weird_tales': r'\bweird tales',
'#literary_(*importance)': r'\bliterary[^.]*\bimportance',
}"
book = open_book("Cthulhu Mythos.epub")
lines = convert_epub_to_lines(book)
with open("test_dict.txt", "r") as data:
tags_dict = ast.literal_eval(data.read())
print(colorama.Back.YELLOW + 'Matches(regex - book text):',colorama.Style.RESET_ALL)
temp = []
res = dict()
for line in lines:
for key,value in tags_dict.items():
if re.search(rf'{value}', line):
if value not in temp:
temp.append(value)
res[key] = value
regex = re.compile(value)
match_array = regex.finditer(line)
match_list = list(match_array)
for m in match_list:
print(colorama.Fore.MAGENTA + key, ":",colorama.Style.RESET_ALL + m.group())
print('\n',colorama.Back.YELLOW + 'Found tags:',colorama.Style.RESET_ALL)
temp = []
res = dict()
for line in lines:
for key,value in tags_dict.items():
if re.search(rf'{value}', line):
if value not in temp:
temp.append(value)
res[key] = value
print(colorama.Fore.GREEN + key, end=", ")
print('\n\n' + colorama.Back.YELLOW + "N° found tags:",colorama.Style.RESET_ALL, len(temp))
This prints:
Matches(regex - book text):
#story_(*writer) : story writer
#publication_(*history) : publication in the history
#horror_fiction : horror fiction
#published_(*books) : published three books
#books_(*poems) : books of poems professionally, and had even sold a couple of prose poem
#new_discovery : new discovery
#literary_(*importance) : literary outpouring of prodigious wordage and importance
Found tags:
#story_(*writer), #publication_(*history), #horror_fiction, #published_(*books), #books_(*poems), #new_discovery, #literary_(*importance),
N° found tags: 7
https://i.stack.imgur.com/iBE1f.png
The truth is that my knowledge of python is very poor, I only learned about regular expressions thanks to Calibre.
I'd appreciate any help with the code, thank you very much.

how to edit this module to search book sets effectively? [duplicate]

This question already has answers here:
Python's "in" set operator
(6 answers)
Closed 1 year ago.
i am practicing sets in python and wrote the below script to search books. it works but not proper ly(please see it below). How can i fix the problem?
book_set = {"Harry Potter", "Angels and Demons", "Atlas Shrugged"}
q = input('Search our Catalog: ')
for book in book_set:
if book == q:
print(book)
else:
print('sorry We ran out of this book')
my expected result should be the title of book if present and the strint('sorry We ran out of this book') if the book doesn't exists in book_set without any more results but see the example
enter code here
Output
Search our Catalog: Harry Potter
Harry Potter
sorry We ran out of this book
You can use in keyword instead of for loop:
book_set = {"Harry Potter", "Angels and Demons", "Atlas Shrugged"}
q = input('Search our Catalog: ')
print("We have that book" if q in book_set "We don't have that book")
The problem you have is that you are going through every book and if it is the book you print it but if it isn't you say you ran out, but for every single book. What you probably want to do is only say you ran out if the book isn't in the set which you can do by doing
book_set = {"Harry Potter", "Angels and Demons", "Atlas Shrugged"}
q = input('Search our Catalog: ')
if q not in book_set:
print("We don't have that book")
else:
# code for when the book is in stock

Python - Replacing a specific value in a CSV file while keeping the rest

So I have a CSV file that looks something like this:
Username,Password,Name,DOB,Fav Artist,Fav Genre
Den1994,Denis1994,Denis,01/02/1994,Eminem,Pop
Joh1997,John1997,John,03/04/1997,Daft Punk,House
What I need to be able to do is let the user edit and change their Fav Artist and Fav Genre so that their new values are saved to the file in place of the old ones. I'm not the very advanced when it comes to CSV so I'm not sure where to begin with it, therefore any help and pointers will be greatly appreciated.
Thanks guys.
EDIT:
Adding the code I have so far so it doesn't seem like I'm just trying to get some easy way out of this, generally not sure what to do after this bit:
def editProfile():
username = globalUsername
file = open("users.csv", "r")
for line in file:
field = line.split(",")
storedUsername = field[0]
favArtist = field[4]
favGenre = field[5]
if username == storedUsername:
print("Your current favourite artist is:", favArtist,"\n" +
"Your current favourite genre is:",favGenre,"\n")
wantNewFavArtist = input("If you want to change your favourite artist type in Y, if not N: ")
wantNewFavGenre = input("If you want to change your favourite genre type in Y, if not N: ")
if wantNewFavArtist == "Y":
newFavArtist = input("Type in your new favourite artist: ")
if wantNewFavGenre == "Y":
newFavGenre = input("Type in your new favourite genre: ")
This is how it would look like using pandas
import pandas as pd
from io import StringIO
# Things you'll get from a user
globalUsername = "Den1994"
field = 'Fav Artist'
new_value = 'Linkin Park'
# Things you'll probably get from a data file
data = """
Username,Password,Name,DOB,Fav Artist,Fav Genre
Den1994,Denis1994,Denis,01/02/1994,Eminem,Pop
Joh1997,John1997,John,03/04/1997,Daft Punk,House
"""
# Load your data (e.g. from a CSV file)
df = pd.read_csv(StringIO(data)).set_index('Username')
print(df)
# Now change something
df.loc[globalUsername][field] = new_value
print(df)
Here df.loc[] allows you to access a row by the index. In this case Username is set as index. Then, [field] selects the column in that row.
Also, consider this:
df.loc[globalUsername][['Fav Artist', 'Fav Genre']] = 'Linkin Park', 'Nu Metal'
In case you have a my-data.csv file you can load it with:
df = pd.read_csv('my-data.csv')
The code above will return
Password Name DOB Fav Artist Fav Genre
Username
Den1994 Denis1994 Denis 01/02/1994 Eminem Pop
Joh1997 John1997 John 03/04/1997 Daft Punk House
and
Password Name DOB Fav Artist Fav Genre
Username
Den1994 Denis1994 Denis 01/02/1994 Linkin Park Pop
Joh1997 John1997 John 03/04/1997 Daft Punk House
Try this
import pandas as pd
data = pd.read_csv("old_file.csv")
data.loc[data.Username=='Den1994',['Fav Artist','Fav Genre']] = ['Beyonce','Hard rock']
data.to_csv('new_file.csv',index=False)
python has a built-in module dealing with csv, there are examples in the docs that will guide you right.
One way to do is to use the csv module to get the file you have into a list of lists, then you can edit the individual lists (rows) and just rewrite to disk what you have in memory.
Good luck.
PS: in the code that you have posted there is no assignment to the "csv in memory" based on the user-input
a minimal example without the file handling could be:
fake = 'abcdefghijkl'
csv = [list(fake[i:i+3]) for i in range(0, len(fake), 3)]
print(csv)
for row in csv:
if row[0] == 'd':
row[0] = 'changed'
print(csv)
the file handling is easy to get from the docs, and pandas dependance is avoided if that is on the wishlist

Web2Py getting/posting values

I'm fairly new to Web2Py and i'm hoping for some help.
I have a reviews DB and a games DB.
At the moment the user can click on a game from a list and they are taken to a page allowing them to leave a review.
I can save the review into the DB but I can't get it to reference the corresponding game.
DB:
db.define_table('games',
Field('title',requires=IS_NOT_EMPTY()),
Field('description','text',requires=IS_NOT_EMPTY()))
db.define_table('reviews',
Field('title',requires=IS_NOT_EMPTY()),
Field('review','text',requires=IS_NOT_EMPTY()))
Default.py:
def review():
getTitle = db.games(request.args(0)) or redirect(URL('default', 'index'))
formReview = SQLFORM(db.reviews,fields = ['title','review']).process()
if formReview.accepted: redirect(URL('index'))
return dict(formReview=formReview, getTitle=getTitle)
Review.html:
{{extend 'layout.html'}}
<h2>Review a game</h2>
<h2>{{=getTitle.title}}</h2>
{{=formReview}}
I'm guessing I need to create a field in 'reviews' that will get the 'request.args' value. But i'm not sure?
You should first expand your review table to hold a foreign key to the games table like this:
db.define_table('reviews',
Field('title',requires=IS_NOT_EMPTY()),
Field('review','text',requires=IS_NOT_EMPTY()),
Field('game_id', 'reference games'))
So you have a reference for which game the review is. With this aditional information you should be able to select all reviews for a game and render them in the view.
for row in db(db.reviews.game_id == 1).select():
print row.title # just an example
And of course you also need to save the corresponding game_id when creating a new review entry ;)
formReview = SQLFORM(db.reviews,fields = ['game_id', 'title','review']).process()

Python sketch not working as intended (reading data from CSV)

I am currently trying to write a program which runs through a CSV file of academic papers. The CSV is tab deliminated and is in four columns (Author, Date, Title, Journal)
The idea is to ask the user whether he wants to search the group of papers via Author, Paper Title or Journal Title (or press Q to quit), and display the results of the query back to the user in this order: Author/s. Year. Title. Journal.
My code runs, but it only retrieves data from the 'search option' I selected. I.E, if I choose to search by Author, it will pull back and display the Authors whose names match the query, but it doesn't display any of the other information (The year, title or journal). This is the same with the other search options (i.e if I select Journal, it will pull back any relevant journals but will not give me the Author, Date or Title of said journal)
Any help here is greatly appreciated! Below is my code.
import csv
def AuthorSearch():
authorSearch = input("Please type Author name. \n")
for item in Author:
if item.find(authorSearch) != -1:
print (item)
def TitleSearch():
titleSearch = input("Please type in Title, \n")
for item in Title:
if item.find(titleSearch) != -1:
print (item)
def JournalSearch():
journalSearch = input("Please type in a Journal, \n")
for item in Journal:
if item.find(journalSearch) != -1:
print (item)
data = csv.reader (open('List.txt', 'rt'), delimiter='\t')
Author, Year, Title, Journal = [], [], [], []
for row in data:
Author.append(row[0])
Year.append(row[1])
Title.append(row[2])
Journal.append(row[3])
print ("Please type in capitals.")
searchOption = input("Press A to search for Author, T to search titles or J to search Journals or press Q to quit. \n" )
if searchOption == 'A':
AuthorSearch()
elif searchOption == 'T':
TitleSearch()
elif searchOption == 'J':
JournalSearch()
elif searchOption == 'Q':
exit()
Thank you very much to anybody who helps, it's really appreciated!
I have googled and read the CSV reference page, but I can't seem to get my head around it. Aagin, all help is appreciated!
The list Author doesn't contain anything but the authors. When you do for item in Author, you are only looking through the authors. When you then print the found item, it is of course only the author. You have the same problem with each field. You have four separate lists of fields that are not linked in any way.
I would suggest you take a look at the pandas library, which has nice facilities for reading CSV files into a tabular data structure. It also does a lot more than that, but it should easily handle what you want to do here.
Your issue is that you put all your info into separate arrays...but you did that because you know their column numbers...so just keep it as is and call by the number!
everything = []
for row in data:
everything.append[row]
Here is an example for your title search function:
def TitleSearch():
titleSearch = input("Please type in Title, \n")
for row in everything:
title = row[2]
if title.find(titleSearch) != -1:
print row
so now you take the entire row, and just run your find() on the 3rd column (the one you said was title) and if it's the same as your titleSearch it will print the entire row with all of the information, problem solved!

Categories