问题 java 8嵌套流


假设你有这样的结构类:

public class Review{
    private Integer idReview;
    private String description;
    private ArrayList<RelReviewImage> images;
}

public class RelReviewImage{
    private Integer idRelReviewImage;
    private Integer idImage;
    private String name;
}

使用Java 8和 Stream我们想要做一个过滤器 idImage 并返回 Review 对象。
可能吗?一个级别很简单,但有两个级别我们找不到任何示例或文档。


13003
2017-12-01 18:37


起源

你的问题不清楚 - 你能展示一个带输入和预期输出的代码示例吗? - assylias


答案:


猜猜你需要什么:(假设有吸气剂可用 Review 和 RelReviewImage

List<Review> originalReviews = ...

List<Review> result = originalReviews.stream()
    .filter(review -> review.getImages().stream() //Nested streams. Assume getImages() never null, but empty 
                          .anyMatch(image -> image.getIdImage() == 123)) //'2 level' here
    .collect(Collectors.toList());

14
2017-12-02 02:05





我认为你可以通过不尝试单线程来获得最易于维护和优雅的代码。 :)

当我拥有这些嵌套结构时,我通常会这样做 为每个级别创建一个新方法。因此,当我编码时,我一次只需要一个级别。

尝试拉动检查是否存在图像的部分 imageId 变成一个 Predicate

一个 Predicate 这里有一个 Function 需要你的 Review 并返回一个 Boolean 可以过滤。

public List<Review> filterReviews(){
    Integer idImage = 1;
    List<Review> reviews = new ArrayList<>();
    ...
    List<Review> result = reviews.stream()
            .filter(hasImage(idImage))
            .collect(Collectors.toList());

    return result;
}

private Predicate<Review> hasImage(final Integer idImage){
    return review -> review.images.stream()
            .anyMatch(image -> Objects.equals(image.idImage, idImage));
}

专家提示

如果 filterReviews - 方法已经采取了 Predicate 作为参数,您可以使用相同的方法来过滤内部的所有不同字段 Review,通过不同的 Predicates


2
2017-08-30 08:21



在我看来,添加一个更好 hasImage 方法 Review 只返回普通老的班级 boolean。然后你可以 .filter(Review::hasImage)。这也将封装 images 存储。假设以后你会改变 List<RelReviewImage> images 至 Map<Integer, RelReviewImage> id2image。然后 hasImage 将减少到 return id2image.containsKey(idImage); - Tagir Valeev


这是一些基本的想法:

public static void main(String[] args) {
    // TODO Auto-generated method stub

    List<Review> reviews = new ArrayList<>();
    for(int i = 0; i < 50; i++) {
        List<RelReviewImage> revImg = new ArrayList<>();
        for(int j = 0; j < 5; j++) {
            revImg.add(new RelReviewImage(j, j, "img_"+j));
        }
        reviews.add(new Review(i, "rev" + i, revImg));
    }

    List<Review> result = reviews.stream().filter(r -> r.getImages().stream().anyMatch(i -> i.getIdImage().intValue() < 2)).collect(Collectors.toList());

}

public class Review {
    private Integer idReview;
    private String description;
    private List<RelReviewImage> images;

    public Review(Integer id, String desc, List<RelReviewImage> img) {
        super();
        this.idReview = id;
        this.description = desc;
        this.images = img;
    }

    public Integer getIdReview() {
        return idReview;
    }

    public void setIdReview(Integer idReview) {
        this.idReview = idReview;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public List<RelReviewImage> getImages() {
        return images;
    }

    public void setImages(List<RelReviewImage> images) {
        this.images = images;
    }
}

public class RelReviewImage {
    private Integer idRelReviewImage;
    private Integer idImage;
    private String name;

    public RelReviewImage(Integer id, Integer id_img, String name) {
        super();
        this.idRelReviewImage = id;
        this.idImage = id_img;
        this.name = name;
    }

    public Integer getIdRelReviewImage() {
        return idRelReviewImage;
    }

    public void setIdRelReviewImage(Integer idRelReviewImage) {
        this.idRelReviewImage = idRelReviewImage;
    }

    public Integer getIdImage() {
        return idImage;
    }

    public void setIdImage(Integer idImage) {
        this.idImage = idImage;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

0
2018-01-12 12:45



虽然此代码可以回答这个问题,但提供有关如何和/或解决问题的原因的其他背景将提高答案的长期价值。 - Donald Duck


要求说您要基于idImage进行过滤,idImage是我们的列表ArrayList图像流中的字段
步骤1:

images.stream()
    .filter(idImage->idImage.equals("I123");

如果发现任何匹配,我们的目标将得到满足

第2步:

images.stream()
        .filter(idImage->idImage.equals("I123")
        .findAny()//this will return Optional<RelReviewImage> object which will be populated if object is found also need not worry about null condition
        .isPresent()//this will check if the Optional<RelReviewImage> object was populated

但是我们从哪里获得这个图像流? 它存在于Review类中,因此可以直接说出来 第3步

Review myReview-new Review();
            myReview.getImages.stream()
                            .filter(idImage->idImage.equals("I123")
                            .findAny()
                            .isPresent()

但我们希望拥有所有listOfReviewObjects 假设我们有ListOfReviewObjects

//Ignore below line of code if not clear,bottomLine is you get list of review objects
            List<Review> reviews = IntStream.rangeClosed(0, 10).mapToObj(e->new Review()).collect(Collectors.toList());

步骤4

reviews.stream()
            .filter("XYZ condition")
            .collect(Collectors.toList());

我们的过滤条件与步骤2相同,因此我们对每件作品进行整理

第5步

reviews.stream()
        .filter(review->review.getImages().stream()
                                            .filter(relReviewImage->relReviewImage.getIdImage().intValue()==imageId)
                                            .findAny()
                                            .isPresent())
        .collect(Collectors.toList());

0
2017-09-14 09:53



你能为你的代码添加一些解释(通过编辑答案),以便其他人可以从中学习吗? - Nico Haase
.filter(predicate).findAyn().isPresent() 可以简化为 anyMatch(predicate) (您的解决方案与其他已提供的解决方案相同) - Didier L