0

I have a dictionary with the last and first names of the authors being the key, and the book, quantity, and price being the values. I want to print them out sorted in alphabetical order by the author name, and then by the book name.

The author is: Dickens, Charles
The title is: Hard Times
The qty is: 7
The price is: 27.00
----
The author is: Shakespeare, William
The title is: Macbeth
The qty is: 3
The price is: 7.99
----
The title is: Romeo And Juliet
The qty is: 5
The price is: 5.99 

I'm very new to dictionaries and can't understand how you can sort a dictionary. My code so far is this:

def displayInventory(theInventory):
    theInventory = readDatabase(theInventory)
    for key in theInventory:
        for num in theInventory[key]:
            print("The author is", ' '.join(str(n) for n in key))
            print(' '.join(str(n) for n in num), '\n')

The dictionary, when printed, from which I read this looks like this:

defaultdict(<class 'list'>, {('Shakespeare', 'William'): [['Rome And Juliet', '5', '5.99'], ['Macbeth', '3', '7.99']], ('Dickens', 'Charles'): [['Hard Times', '7', '27.00']]})
  • 1
    Dictionaries are inherently orderless, so you wouldn't sort them. This related question seems to have produced a pretty good answer though: http://stackoverflow.com/questions/613183/python-sort-a-dictionary-by-value The idea would be to produce a list from the dictionary contents and sort that. – user2027202827 May 05 '14 at 03:24
  • I asked incorrectly the first time. I have included the list that I made in the question now. –  May 05 '14 at 03:34

2 Answers2

1

fwiw, camelCase is very uncommon in Python; almost everything is written in snake_case. :)

I would do this:

for names, books in sorted(inventory.items()):
    for title, qty, price in sorted(books):
        print("The author is {0}".format(", ".join(names)))
        print(
            "The book is {0}, and I've got {1} of them for {2} each"
            .format(title, qty, price))
        print()

Ignoring for the moment that not everyone has a first and last name...

There are some minor tricks involved here.

  • First, inventory.items() produces a list of key, value tuples. I can then sort that directly, because tuples sort element-wise — that is, (1, "z") sorts before (2, "a"). So Python will compare the keys first, and the keys are tuples themselves, so it'll compare last names and then first names. Exactly what you want.

  • I can likewise sort books directly because I actually want to sort by title, and the title is the first thing in each structure.

  • I can .join the names tuple directly, because I already know everything in it should be a string, and something is wrong if that's not the case.

  • Then I use .format() everywhere because str() is a bit ugly.

Eevee
  • 47,412
  • 11
  • 95
  • 127
  • Is there a way to format this to view an author's work specifically? And if the author is not in the dictionary, will that raise an error? –  May 05 '14 at 04:39
  • well, you could move the inner loop into a function, and do `books = inventory["Shakespeare", "William"]` to get the right list of books. and yes you'll get a `KeyError`. – Eevee May 05 '14 at 05:25
0

The key is to use sorted() to sort the dictionary by its keys, but then use sort() on the dictionaries values. This is necessary because your values are actually a list of lists and it seems you want only to sort them by the first value in each sub-list.

theInventory = {('Shakespeare', 'William'): [['Rome And Juliet', '5', '5.99'], ['Macbeth', '3', '7.99']], ('Dickens', 'Charles'): [['Hard Times', '7', '27.00']]}

for Author in sorted(theInventory.keys()):
    Author_Last_First = Author[0]+", "+Author[1]
    Titles = theInventory[Author]
    Titles.sort(key=lambda x: x[0])
    for Title in Titles:
        print("Author: "+str(Author_Last_First))
        print("Title: "+str(Title[0]))
        print("Qty: "+str(Title[1]))
        print("Price: "+str(Title[2]))
        print("\n")

Is that what you had in mind? You can of course always put this in a function to make calling it easier.

user2027202827
  • 1,234
  • 11
  • 29
  • 1
    `.sort` means you mutate the original dict, which may be impolite. tuple unpacking is much easier to follow than explicit indexing. you don't need `.keys()`; iterating a dict directly produces its keys. and `Capital_Underscores` is really weird :) – Eevee May 05 '14 at 04:19
  • Thanks for the thoughts :) Why would you prefer .format() to str()? – user2027202827 May 05 '14 at 04:22
  • `str()` and concatenation requires breaking your string up into pieces, whereas a format string lets you see roughly what the result looks like at a glance. `.format` is also easier to wrap by virtue of being a method. and concatenation is O(n²), not that it matters a whole lot here – Eevee May 05 '14 at 04:28