0

I've created this code to show what books people haven't read at a Bookclub.

The code I have written is

Books = {}
Names = []
temp1 = set()
line = input('Book read: ')
while line:
  Book, Name = line.split(':')
  if Book not in Books:
    # add it to our dictionary as a list with one element
    Books[Book] = [Name]
  else:
    Books[Book].append(Name)
  line = input('Book read: ')
  
  if Name not in Names :
    Names.append(Name)
    
Names = list(dict.fromkeys(Names))

for Name in Names:
  temp1.add(Name)
  
BookSorted = dict(sorted(Books.items()))

for Book in BookSorted:
  if BookSorted[Book] == Names :
    print(Book + ": Everyone has read this!")
  else:
    temp2 = set(BookSorted[Book])
    print(Book, ':', ', '.join(temp1 - temp2))

Which does work, but both the list of books and the names don't come out in alphabetical order. (I have removed my various attempts so you can read it easier).

When presented with the following test sample

Book read: Pride and Prejudice:Jenny
Book read: A Tale of Two Cities:Mark
Book read: Magician:Jenny
Book read: The Lord of the Rings:Pavel
Book read: Magician:Pavel

My code returns

Pride and Prejudice: Mark, Pavel
A Tale of Two Cities: Pavel, Jenny
Magician: Mark
The Lord of the Rings: Mark, Jenny

When it should return

A Tale of Two Cities: Jenny, Pavel
Magician: Mark
Pride and Prejudice: Mark, Pavel
The Lord of the Rings: Jenny, Mark

Any help would be much appreciated :)

Kindest Regards

  • I suggest you check out this answer: https://stackoverflow.com/a/613218/11535766 It might help you – kkubina Aug 06 '20 at 12:46
  • 1
    Does this answer your question? [How do I sort a dictionary by value?](https://stackoverflow.com/questions/613183/how-do-i-sort-a-dictionary-by-value) – Maurice Meyer Aug 06 '20 at 12:48

2 Answers2

0

Giving a dict with book titles as keys and readers as values you can do something like this:

data = {
    "Pride and Prejudice": ["Mark", "Pavel"],
    "A Tale of Two Cities": ["Pavel", "Jenny"],
    "Magician": ["Mark"],
    "The Lord of the Rings": ["Mark", "Jenny"]
}

data = dict(sorted(data.items()))


# just a short print loop to show you the order

for k,v in data.items():
    print(k+":"+str(v))

#A Tale of Two Cities:['Pavel', 'Jenny']
#Magician:['Mark']
#Pride and Prejudice:['Mark', 'Pavel']
#The Lord of the Rings:['Mark', 'Jenny']
MisterNox
  • 1,445
  • 2
  • 8
  • 22
  • This is generally a bad plan--as is most any plan to sort a dictionary. any new addition to this will blow up the sort. – AirSquid Aug 06 '20 at 16:09
  • This comment is not really helpful, but thanks. Of course it will blow the order. Thats why you only have to do a sort when you want to return the ordered output right after it. But you propbaly want to share your idea with us. – MisterNox Aug 06 '20 at 16:13
0

The comments and other solution have good discussion of sorting and dictionaries. IMHO, it is dangerous to think/assume a dictionary or set is sorted because by design, they are not intended to be ordered. With the caveats in the other ideas, you could do it, or switch over to OrderedDict, which has some overhead. My suggestion is to just "sort the keys" when you need to. Of course if you find need to do that a LOT, then that is motivation to switch to different data structure.

Here is a cut at this, with a few other enhancements:

  • use set when you are going to do set-like things such as intersection/difference. It is much cleaner
  • Don't use upper case for variable names... python standard is lower case
  • you almost certainly want to strip() lead/trailing whitespace from entries so you don't get hung up on the difference between:

Cat in Hat: Bob
Cat in Hat:Bob

# sorting books

books = {}          # title : set of readers
all_names = set()   # all reader names set
line = input('Enter book title : name ')
while line:
  book, name = [t.strip() for t in line.split(':')]   # strip out pesky leading/trailing spaces.
  if book not in books:
    # add it to our dictionary as a list with one element
    books[book] = {name, }  # a set with one item
  else:
    books[book].add(name)
  
  all_names.add(name)       # set will not accept duplicates, so this works...
    
  line = input('Enter book title : name ')

# now we have a dictionary of book : set of names that have read it
# and a set of all names that we can use

for k in sorted(books):  # sort the keys only when needed
  non_readers = all_names ^ books[k]
  # note: ^ is symmetric difference, so result will be names in all_names that are not in readers
  if non_readers:  # non-empty response
    print(f'{k} has not been read by: {", ".join(sorted(non_readers))}')
  else:
    print(f'Everyone has read {k}')

After tinkering with this, I realize you probably aren't running a book club and this is likely a H/W assignment, so now I feel bad about this... lol.

AirSquid
  • 10,214
  • 2
  • 7
  • 31