使用Java Lambda Stream的方法:给出一本有书的学生名单,找到所有阅读最便宜书的学生

时间:2019-07-19 18:49:58

标签: java lambda java-8 java-stream

我只是想玩lambda和流。说我有拥有图书集的图书清单。我想找出正在读最便宜书的学生姓名。我应该能够以最低价获得这本书。我能够以最低价获得本书,但如何获得学生姓名?

编辑:我更新如下。有什么更好的方法吗?

    Supplier<List<Student>> studentListSupplier = () -> {
            return createStudentList2();
        };
        Book bookWithMinPrice=studentListSupplier.get().stream().flatMap(sl->sl.getBookSet().stream()).min(new BookComparator()).get();
        List<Student> studentsHavingbookWithMinPrice = new ArrayList<>();
        studentListSupplier.get().forEach(s->{
            if(s.getBookSet().contains(bookWithMinPrice)){
                studentsHavingbookWithMinPrice.add(s);
            }

        });


class Student {
    private String name;
    private Set<Book> bookSet;
    ////
}

class Book {
    int price;
    String name;
    ////  
}
 //DataSet
private static List<Student> createStudentList2() {
        Set<Book> bookSet1 =   new HashSet<>();
        Book b11=new Book(10, "AAA");
        bookSet1.add(b11);
        Book b12= new Book(20, "BBB");
        bookSet1.add(b12);

        Set<Book> bookSet2 =   new HashSet<>();
        Book b21=new Book(30, "XXX");
        bookSet2.add(b21);
        Book b22= new Book(15, "ZZZ");
        bookSet2.add(b22);
        Book b23 =  new Book(10, "KKA");
        bookSet2.add(b23);

        Student s1 = new Student();
        s1.setBookSet(bookSet1);
        s1.setName("s1");

        Student s2 = new Student();
        s2.setBookSet(bookSet2);
        s2.setName("s2");

        Student s3 = new Student();
        s3.setBookSet(bookSet1);
        s3.setName("s3");

        List<Student> studentListWithBooks = Arrays.asList(s1,s2,s3);
        return studentListWithBooks;
    }

2 个答案:

答案 0 :(得分:1)

您可以这样做:

Student studentWithCheapestBook = students.stream()
    .min(comparingInt(s -> Collections.min(s.getBookSet(), comparingInt(Book::getPrice)).getPrice()))
    .orElse(null);

Collectors.comparingInt作为静态导入。

您也可以使用comparingInt(Book::getPrice)代替BookComparator。 :)

如果您需要所有学生,那么您将无法完成一个工作流。您需要先计算最便宜的价格,然后相应地过滤学生列表。

int cheapestPrice = students.stream()
    .flatMap(s -> s.getBookSet().stream())
    .mapToInt(Book::getPrice)
    .min().orElse(0);

Set<Student> readingCheapestBooks = students.stream()
    .collect(filtering(s -> s.getBookSet().stream().anyMatch(b -> b.getPrice() <= cheapestPrice), 
             toSet()));

我刚刚发现,自Java 9起就有Collectors.filtering。 :)

答案 1 :(得分:1)

要找到所有阅读最便宜的书(复数)的学生(复数),您首先需要找到最便宜的价格,然后找到按此价格有书的学生。

int minPrice = students.stream()
        .flatMap(s -> s.getBookSet().stream())
        .mapToInt(Book::getPrice)
        .min().orElse(Integer.MIN_VALUE);
List<Student> studentsHavingBookWithMinPrice = students.stream()
        .filter(s -> s.getBookSet().stream().anyMatch(b -> b.getPrice() == minPrice))
        .collect(Collectors.toList());

如果没有书籍,orElse(Integer.MIN_VALUE)将确保结果列表为空。比getAsInt()更好,如果没有书籍,后者会引发异常。