Home > Blockchain >  How to filter a list of objects by matching properties with objects from another list
How to filter a list of objects by matching properties with objects from another list

Time:10-18

I'm a Programming student in Java II. I have an object Publication that has two properties... a list of Books and a List of Authors

public class Publication {
    
    public final List<Book> bookList;   
    public final List<Author> authorList;
}

public class Author {
    private final String id;
    private final String firstName;
    private final String lastName;
    private final  int age;
}
public class Book {
    private final String title;
    private final String authorId;     //this is equal to person's id who wrote the book
}   

My task is to create a method

public List<Book> getBooksByAuthorAge(int age){}

in the Publication class that accepts an int age, and then returns all Books that were written by an author of that age. The Book property "authorId" correlates to the Author property "id". So i need to take the age, find the people of that age, find their id's, then filter the list of books by an authorId that's in a list of authors who are that age.

I'm still a little weak by comparison in Java and trying to do it with streams, but at every step I'm thwarted. I've started to break it into multiple statements, first returning a list of persons with the given age and then using that to map a list of ID's that I could then use to compare to the authorIds but I'm struggling in the stream and I don't want to go back to old for loops for Java I! I know it's too dumb to have a bunch of variables tied up in this little method. Can any off you people who make beautiful streams give me a little nudge? Greatly appreciated in advance, really!

The following is only partway done AND it's too dumb, but included just to demonstrate where my mind is stuck in the mud:

//a List of authors who are of that age
        List<Author> agedResults = authorList.stream()
                .filter(p -> p.getAge() == age)
                .collect(Collectors.toList());
        
        //a list of IDs that belong to authors of that age
        List<String> agedIds = agedResults.stream()
                .map(Author::getId)
                .collect(Collectors.toList());

CodePudding user response:

Instead of maintaining authorId in Book, I suggest you add a Author field. Anyway, as is, first stream the authorList to collect the matching authorIds then stream the bookList to find books that match. Like,

public List<Book> getBooksByAuthorAge(int age) {
    List<String> authorIds = authorList.stream()
            .filter(a -> a.age == age).map(a -> a.id)
            .collect(Collectors.toList());
    return bookList.stream()
            .filter(book -> authorIds.contains(book.authorId))
            .collect(Collectors.toList());
}

CodePudding user response:

It can be so:

public List<Book> getBooksByAuthorAge(int age) {
        return bookList.stream()
                .filter(book -> authorList.stream()
                        .filter(author -> author.getAge() == age)
                        .anyMatch(author -> Objects.equals(author.getId(), book.getAuthorId())))
                .collect(Collectors.toList());
    }

but i'm not sure that it better then several variables. Code should be readable and streams not always correspond for this requirement.

  • Related