嵌套在Lambdas中设置块迭代和范围

时间:2017-09-25 15:17:22

标签: java lambda java-8

希望有人能解决这个问题。

对象结构我有一个类似于

的对象结构

主要对象是学生,学生获得一些信件

 public class LetterRange {
    private Date letterStartDate;
    private Date letterEndDate;

    public Date getLetterStartDate() {
        return letterStartDate;
    }

    public void setLetterStartDate(Date letterStartDate) {
        this.letterStartDate = letterStartDate;
    }

    public Date getLetterEndDate() {
        return letterEndDate;
    }

    public void setLetterEndDate(Date letterEndDate) {
        this.letterEndDate = letterEndDate;
    }
}

public class Letters {
    private String letterName;
    private Set<LetterRange> letterRangeSet;

    public String getLetterName() {
        return letterName;
    }

    public void setLetterName(String letterName) {
        this.letterName = letterName;
    }

    public Set<LetterRange> getLetterRangeSet() {
        return letterRangeSet;
    }

    public void setLetterRangeSet(Set<LetterRange> letterRangeSet) {
        this.letterRangeSet = letterRangeSet;
    }
}

public class Student {
    private String name;
    Set<Letters> lettersSet;

    public String getName() {
        return name;
    }

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

    public Set<Letters> getLettersSet() {
        return lettersSet;
    }

    public void setLettersSet(Set<Letters> lettersSet) {
        this.lettersSet = lettersSet;
    }
}
public class StudentRunner {
    public static void main(String args[]){
    List<Student> studentList = new ArrayList<>();
    Student one = new Student();
    Student two= new Student();
    Student three= new Student();
    one.setName("John");

    Letters johnLetter1 = new Letters();
    johnLetter1.setLetterName("Kudos");

    Letters janeLetter = new Letters();
    janeLetter.setLetterName("Jane Kudos");

    Letters otherJaneLetter = new Letters();
    otherJaneLetter.setLetterName("Other Jane letter");


    one.setLettersSet(new HashSet<Letters>() {{
        add(johnLetter1);
        add(janeLetter);
        add(otherJaneLetter);
    }});

    two.setLettersSet(new HashSet<Letters>(){{
        add(johnLetter1);
        add(janeLetter);
    }});

    LetterRange johnLetter1Range = new LetterRange();
    johnLetter1Range.setLetterStartDate(new Date());
    johnLetter1Range.setLetterEndDate(new Date());

    LetterRange johnLetter2Range = new LetterRange();
    johnLetter1Range.setLetterStartDate(DateTime.now().plus(10).toDate());
    johnLetter1Range.setLetterEndDate(DateTime.now().plus(10).toDate());

    johnLetter1.setLetterRangeSet(new HashSet<LetterRange>() {{
        add(johnLetter1Range);
        add(johnLetter2Range);
    }});

    studentList.add(one);

    Set dataSet = studentList.stream().flatMap(student -> student.getLettersSet().stream())
            .collect(Collectors.toSet());


   Letters dataMap= studentList.stream().flatMap(student -> student.getLettersSet().stream()).filter(letters -> StringUtils.contains(letters.getLetterName(),"Jane")).findAny().orElseThrow(
        NoSuchElementException::new);
    System.out.println(dataMap);
    System.out.println(studentList.stream().flatMap(student -> student.getLettersSet().stream()).filter(letters -> StringUtils.contains(letters.getLetterName(),"Jane")).collect(Collectors.toSet()));
    Assert.assertTrue(dataSet.size() == 1);
    }
}

我试图让lambda根据过滤条件返回所有学生(最外面的对象列表)。我知道我们可以迭代旧的方式,但我想看看是否有一个lambda可以帮助我。 TIA。

2 个答案:

答案 0 :(得分:6)

你需要的是2张平面地图:

Set<LetterRange> rangeOfLetters = studentList.stream()
        .flatMap(x -> x.letterSet.stream())
        .flatMap(x -> x.letterRanges.stream())
        .collect(Collectors.toSet());

平面地图操作可以改变这一点:

[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

进入这个:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

您的数据结构如下:

[
    <
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange}
    >,
    <
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange}
    >,
    <
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange}
    >
]

[]代表最外面的一组。 <>表示学生对象,{}表示字母对象。

第一张平面地图将数据转换为:

    [
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange},
        {LetterRange, LetterRange, LetterRange}
    ]

第二张平面地图将数据转换为:

[
    LetterRange, LetterRange, LetterRange,
    LetterRange, LetterRange, LetterRange,
    LetterRange, LetterRange, LetterRange,
    LetterRange, LetterRange, LetterRange,
    LetterRange, LetterRange, LetterRange,
    LetterRange, LetterRange, LetterRange,
    LetterRange, LetterRange, LetterRange,
    LetterRange, LetterRange, LetterRange,
    LetterRange, LetterRange, LetterRange
]

答案 1 :(得分:4)

解决这个问题的方法是使用中间变量并查看每个阶段的结果。

Stream<Student> studentStream = studentList.stream();

......是一个好的开始。您可以自己选择studentStream的类型,并且能够做到这一点很好。但是你的IDE会告诉你它是否错了 - 你甚至可以让IDE为你输入正确的类型。

您知道自己需要flatMap,因为您知道自己正在展平嵌套结构。您传递给flatMap的功能必须使用Student并返回Stream<?>,因此您的选项有限:

Stream<Letters> lettersStream = studentStream.flatMap(
    stu -> stu.getLettersSet().stream());

Stream<Letters>接近你的目标与以前的思路基本相同:

Stream<LetterRange> letterRangeStream = lettersStream.flatMap(
     ls -> ls.getLetterRangeSet().stream());

......现在你有你想要的东西;你只需要把它收集到List

List<LetterRange> letterRanges = letterRangeStream.collect(Collectors.toList());

您可以选择保留:

    Stream<Student> studentStream = studentList.stream();
    Stream<Letters> lettersStream = studentStream.flatMap(
          stu -> stu.getLettersSet().stream());
    Stream<LetterRange> letterRangeStream = lettersStream.flatMap(
          ls -> ls.getLetterRangeSet().stream());
    List<LetterRange> letterRanges = letterRangeStream.collect(Collectors.toList());

......这很好 - 无论如何,JRE将优化中间变量。但是,如果您愿意,可以将它们(通过手动,或使用IDE&#34;内联变量&#34;重构工具)内联到:

List<LetterRange> letterRanges = studentList.stream()
   .flatMap(stu -> stu.getLettersSet().stream())
   .flatMap(ls -> ls.getLetterRangeSet().stream())
   .collect(Collectors.toList());