Filter for author exact match regardless of case

Question:

I have a linked list for a catalog and book. I am trying to filter by author and return with the books that are of exact match, however, it says that my book type has no such attribute whenever i run it. I also try to upper case the author names so that it is consistent and match will return even if input are of different case

class Book:
    def __init__(self, title, author, year):
        if not isinstance(title, str):
            raise Exception("title must be a string")
        if not isinstance(author, str):
            raise Exception("author must be a string")
        if not isinstance(year, int):
            raise Exception("year must be an integer")

        self.title = title
        self.author = author
        self.year = year

    def __eq__(self, other):
        if isinstance(other, Book):
            return self.title == other.title and 
                self.author == other.author and 
                 self.year == other.year
        return NotImplemented

    def __repr__(self):
        return f"{repr(self.title)} by {repr(self.author)} {self.year})"


class Catalog:
    def __init__(self):
        self.lst = []

    def filter_by_author(self, author):
        xs = self.lst.copy()
        xs = [author.capitalize() for author in xs]
        if author.upper() in xs:
            return self.lst

# driver

b1 = Book("1984", "George Orwell", 1949)
b2 = Book("Brave new world", "Aldous Huxley", 1932)
b3 = Book("El aleph", "Jorge Louis Borges", 1949)
b4 = Book("The devils of Loudun", "Aldous Huxley", 1952)

cat = Catalog()

cat.add(b1)
cat.add(b2)
cat.add(b3)
cat.add(b4)


la = cat.filter_by_author("aldous huxley")
assert la == [b2, b4]

I am trying to assert if author matches the books in the catalog, the list will return with the books

Asked By: user20250841

||

Answers:

You don’t need to make a copy of your lst, since your generator below makes a new list anyway. I also don’t understand why you are using .capitalize()

The problem is that in your list comprehension you go through each book, call the current Book "author" and then try to captialize author. author however is a Book, which you cannot capitalize. In your code you’d need to call author.author.capitalize(), or you just use the following:

def filter_by_author(self, author):
  author = author.lower()
  return [book for book in self.lst if book.author.lower() == author]

Edit to respond to comment

In python you can easily check whether a string contains a certain substring:

def filter_by_author(self, author):
  author = author.lower()
  return [book for book in self.lst if author in book.author.lower()]

I am not sure however that is what you want, because "John" in "Johnathan" is True. So you’d probably want to check if any of the names are "John"

def filter_by_author(self, author):
  author = author.lower()
  return [book for book in self.lst if author in book.author.lower().split()]

This first splits the string at a certain string. Eg. "John Nathan Last-name".split(" ") == ["John", "Nathan", "Last-name"]
The arguments default value is " ", so you don’t need to pass it in.

Answered By: emilyisstewpid

add() was not defined.

str.capitalize() is different from str.upper()

do not return self.lst itself

class Catalog:
    def __init__(self):
        self.lst = []

    def add(self, b):
        self.lst.append(b)

    def filter_by_author(self, author):
        return [b for b in self.lst if b.author.upper() == author.upper()]
Answered By: gashik
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.