【问题标题】:Filter based on the value of previous elements in the list根据列表中先前元素的值进行过滤
【发布时间】:2021-12-29 14:30:26
【问题描述】:

我有一个如下所示的对象列表:

class Test {
    String a;
    int sortKey;
}

List<Test> testList; 

这个testList是根据sortKey排序的。

我想在testList 中找到第一个Test 对象,其中a 的值是"X",并且列表中所有先前Test 对象的值是@987654329 @

这就是我正在尝试的

testList
    .stream()
    .sorted(sortBasedOnSortKey())
    .filter(test -> test.a().equals("X"))
    .findFirst();

如何确保前面的元素的值为a == "Y"

【问题讨论】:

  • 不能真的用流做到这一点。使用正常循环。
  • @LouisWasserman 这可以通过Stream::takeWhile完成
  • 即使takeWhile 也无法验证元素是否都是Y,直到最后一个值为X。您一次只能检查其中一项。
  • @LouisWasserman、takeWhile (X or Y) 然后是filter (X)/dropWhile(Y)findFirst。很简单。

标签: java filter java-stream


【解决方案1】:

嗯,你可以结合takeWhiledropWhile

Test[] tests = {
    new Test("Y", 1),
    new Test("Y", 2),
    new Test("Y", 3),
    new Test("X", 4), // Expecting to yield this value
    new Test("O", 5),
    new Test("X", 6),
    new Test("X", 7)
};
Optional<Test> test = Stream.of(tests)
    .takeWhile(t -> t.a().equals("X") || t.a().equals("Y"))
    .dropWhile(t -> t.a().equals("Y"))
    .findFirst();

【讨论】:

    【解决方案2】:
    1. 在流​​之前对列表进行排序。
    2. 使用IntStream,找到匹配过滤器"X".equals(a)的第一个元素的索引
    3. 如果找到这样的索引,检查索引之前的所有元素是否匹配另一个过滤器"Y".equals(a)
    static Test findFirstAfterAll(String first, String all, List<Test> testList) {
        testList.sort(Comparator.comparingInt(Test::getSortKey));
        int index = IntStream
                .range(0, testList.size())
                .filter(i -> first.equals(testList.get(i).getA()))
                .findFirst()
                .orElse(-1);
    
        return IntStream.range(0, index)
                .allMatch(i -> all.equals(testList.get(i).getA())) 
                    ? testList.get(index) : null;
    }
    

    测试:

    List<Test> testList = Arrays.asList(
            new Test("X", 20),
            new Test("Y", 15),
            new Test("Y", 12)
    );
    
    System.out.println(findFirstAfterAll("X", "Y", testList));
    

    输出:

    Test(a=X, sortKey=20)
    

    假设 a.equals("Y")no 元素可能出现在“X”之前,使用 Java 9 Stream::takeWhile 也可以工作:

    static Optional<Test> findFirstAfterAll(String first, String all, List<Test> testList) {
        return testList.stream()
                .sorted(Comparator.comparingInt(Test::getSortKey))
                .takeWhile(t -> all.equals(t.getA()) || first.equals(t.getA()))
                .filter(t -> first.equals(t.getA()))
                .findFirst();
    }
    

    测试:

    System.out.println(findFirstAfterAll("X", "Y", Arrays.asList(new Test("Y", 20), new Test("X", 15), new Test("X", 12))));
    
    System.out.println(findFirstAfterAll("X", "Y", Arrays.asList(new Test("X", 20), new Test("Y", 15), new Test("Y", 12))));
    
    System.out.println(findFirstAfterAll("X", "Y", Arrays.asList(new Test("Y", 20), new Test("Y", 15), new Test("Y", 12))));
    
    System.out.println(findFirstAfterAll("X", "Y", Arrays.asList(new Test("Y", 20), new Test("X", 15), new Test("A", 12))));
    

    输出:

    Optional[Test{a='X', sortKey=12}]
    Optional[Test{a='X', sortKey=20}]
    Optional.empty
    Optional.empty
    

    逻辑是只有“X”或“Y”可能出现在排序列表的开头,只要找到“X”就可以了。


    如果必须在 X 之前出现至少一个“Y”才能进行有效匹配,则可以实施使用 takeWhile 的类似解决方案:

    static Optional<Test> findFirstAfterAtLeastOne(String first, String all, List<Test> testList) {
        testList.sort(Comparator.comparingInt(Test::getSortKey));
        
        int index = (int) IntStream.range(0, testList.size())
            .takeWhile(i -> all.equals(testList.get(i).getA()))
            .count();
    
        return index == 0 
            ? Optional.empty() 
            : IntStream.range(index, testList.size())
                .takeWhile(i -> first.equals(testList.get(i).getA()))
                .mapToObj(testList::get)
                .findFirst();
    }
    

    这里相同测试数据的输出是:

    Optional.empty   // no Y before X
    Optional[Test{a='X', sortKey=20}]
    Optional.empty
    Optional.empty
    

    【讨论】:

      猜你喜欢
      • 2020-02-29
      • 2017-08-06
      • 1970-01-01
      • 2019-10-22
      • 1970-01-01
      • 2017-08-12
      • 1970-01-01
      • 1970-01-01
      • 2018-07-14
      相关资源
      最近更新 更多