Jon-Paul
Jon-Paul

Reputation: 469

Filter an array of objects by property, using an array of values in Swift

What is the most efficient way of filtering an array of objects based on one of their properties, using an array of values? I could iterate through the items, but I can't help thinking there's a really efficient way using Array.filter and Array.contains - I'm just not proficient enough with Swift to be able to put the pieces together.

For example, if I have an array containing Book objects, each of which has a String author property, how would I filter it to show only books by John Smith, Arthur Price or David Jones?

Something along the lines of:

Class Book {
    var author : String = String()
}

var books : Array = [Book]()
//books added elsewhere

let authors = ["John Smith", "Arthur Price", "David Jones"]

let filteredBooks = books.filter({authors.contains({($0 as Book).author})})

Upvotes: 15

Views: 24009

Answers (3)

vikingosegundo
vikingosegundo

Reputation: 52227

You could also use something like

let authorsAndBooks = authors.map { 
   (authorName) -> (String, [Book]) 
      in (authorName, 
      allBooks.filter({ $0.author == authorName })
   ) 
 }

This will array of tuples with the first element being the author name and the second element an array of his books, in case an author wrote more than one book.

Upvotes: 6

Jon-Paul
Jon-Paul

Reputation: 469

This is what I have working in a playground, any reason why this is no good?

class Book {
    var author = String()

    init(author:String){
        self.author = author
    }
}

var allBooks: [Book] = []

allBooks.append(Book(author: "John Smith"))
allBooks.append(Book(author: "Arthur Price"))
allBooks.append(Book(author: "David Jones"))
allBooks.append(Book(author: "Somebody Else"))

let authors = ["Arthur Price", "David Jones"]

let filteredBooks = allBooks.filter({authors.contains($0.author)})

filteredBooks       // [{author "Arthur Price"}, {author "David Jones"}]

Upvotes: 20

Arsen
Arsen

Reputation: 10951

I'd recommend you make an index of books by author:

let book = Book(author: "Arsen")
let bookIndex = [book.author: [book]]

And now you have incredible fast access to your book filtered by author:

bookIndex["Arsen"] // => [Books]

For multiple authors:

var results = [Book]()
for author in authors {
    if let books = bookIndex[author] {
        results += books
    }
}

results

Upvotes: 3

Related Questions