Filter an array of objects by property, using an array of values in Swift
Solution 1
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
Solution 2
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"}]
Solution 3
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.
Jon-Paul
Updated on July 28, 2022Comments
-
Jon-Paul over 1 year
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})})
-
Alexey Pichukov over 8 yearsDo you need the easiest way or the most effective? If the most effective then for example you need first prepare the data and convert the array to the dictionary with the key - the search field and value - the
Book
object. After this action your search will be the most effective -
Jon-Paul over 8 years@Alex, how would you apply that method to the command I just added above?
-
Alexey Pichukov over 8 yearsyou're working with an array, in this case, the search may not be as fast as possible, to make it as fast as possible you need to work with dictionary. If you need fast search see answer below from Arsen, there is an example of what I mean
-
-
Jon-Paul over 8 yearsthis looks interesting, but how would you use an index to filter by multiple values?
-
Arsen over 8 years@Jon-Paul check out the update. I think it can be written in one-line style with
map
andflatmap
but still it very efficient way -
Jon-Paul over 8 yearsThanks - and this would be quicker than working with the array as I've suggested?
-
Jon-Paul over 8 yearsTo be clear, I don't need it to be as fast as possible. I'm just interested in using the best design patterns as I learn Swift. :)
-
rd_ over 7 yearsu will get multiple times the same authorName with corresponding book array everytime.