Java 8 Stream - 在特定项目最后一次出现后获取项目

问题描述 投票:0回答:8

我想在列表中最后一次出现特定项目后获取该项目。 例如

List<Bean>  list = ArrayList<Bean>() {{
   add(new Bean(1, null));  // null
   add(new Bean(2, "text2"));
   add(new Bean(3, "text3"));
   add(new Bean(4, "text4"));
   add(new Bean(5, null));   // null last occurence
   add(new Bean(6, "text6");  // want this one.
}}

我想在最后一次出现带有空文本的Bean之后获取该项目,例如上面的 Bean id 6。

非常感谢。

java java-stream
8个回答
2
投票
Atomic

:

 来处理它们
AtomicBoolean isPreviousNull = new AtomicBoolean(false); AtomicReference<Bean> lastOccurrence = new AtomicReference<>(null); list.forEach(item -> { if (item.text == null) { isPreviousNull.set(true); } else if (isPreviousNull.get()) { isPreviousNull.set(false); lastOccurrence.set(item); } }); System.out.println(lastOccurrence.get());



1
投票

Bean firstAfterNull = IntStream.iterate(list.size() - 2, i -> i - 1) .limit(list.size() - 1) //or better .takeWhile(i -> i >= 0) on Java 9+ .filter(i -> null == list.get(i).getText()) .boxed() .findFirst() .map(i -> i + 1) .map(list::get) .orElse(null);



0
投票

Bean lastFound = null; Iterator<Bean> it = list.iterator(); if (it.hasNext()) { Bean prev = it.next(); while (it.hasNext()) { Bean curr = it.next(); if (prev.text == null) { lastFound = curr; } prev = curr; } }

您还可以使用 
ListIterator

反向迭代列表,并在找到第一个匹配项后立即停止。

    


0
投票

Map<String, Bean> map = new HashMap<>(); for (Iterator<Bean> it = list.iterator(); it.hasNext(); ) if (it.next().getText() == null && it.hasNext()) map.put(null, it.next()); System.out.println(map.get(null));

直播版本:

lastFound = IntStream.range(0, list.size()) .collect(() -> new HashMap<String, Bean>(), (m, i) -> { if (list.get(i).getText() == null && (i + 1) < list.size()) m.put(null, list.get(i + 1)); } , HashMap::putAll) .get(null);



0
投票
Stream

的解决方法之一是跟踪

text
Bean
的最后一个索引。
Map<String, Integer> lastIndexMap = IntStream.range(0, list.size())
        .boxed()
        .collect(Collectors.toMap(a -> list.get(a).getText(), a -> a, Integer::max));
    

通过这种方式,您可以轻松访问特定文本的最后一个索引之后的下一个元素。

Bean afterLastIndexOfNull = list.get(lastIndexMap.get(null) + 1);

缺点

尤其是在您的情况下,如果我将null文本值转换为

null
中的
Map
键。应该高度劝阻他们,因此您可以选择实现一个包装器将
null
转换为某些默认文本,然后也基于相同的文本进行查找。

陷阱

    上述方法的问题之一是您在尝试访问时可能会出现数组索引越界异常
  1. list.get(lastIndexMap.get(<key>) + 1)

    
    
  2. 关键文本也出现在列表的最后一个元素中。

  1. Holger 在评论中明确提到的另一点是,这种方法准备了很多信息。

    请注意,根据您进一步查询的内容,需要进行权衡。如果您想准备查找文本列表。这种方法可能对于单次迭代和更快的访问很有用。

    但另一方面,如果这只是一次性计算,那么值得将信息最小化为单个索引。 Holger 也已经提出了解决方案。

    OptionalInt lastIndex = IntStream.range(0, list.size()) .filter(ix -> list.get(ix).getText() == null) .reduce((a, b) -> b);

        
我会简单地从最后开始并倒着工作。请注意,这从倒数第二个元素开始。 如果最后一个元素为 null,则不会返回任何内容。

0
投票
Optional<Bean> opt = IntStream .iterate(list.size() - 2, i -> i >= 0, i -> i - 1) .filter(i -> list.get(i).getText() == null) .mapToObj(i -> list.get(i + 1)).findFirst(); System.out.print( opt.isPresent() ? opt.get().getText() : "None Found");

使用

0
投票
partitioningBy

int index = IntStream.range(0, items.size())
    .boxed()
    .collect(partitioningBy(i -> items.get(i).getText() == null, reducing((l, r) -> r)))
    .get(true).get() + 1;

Bean element = items.get(i);

这依赖于定位元素。如果此类元素不存在,则会抛出
NoSuchElementException

ArrayIndexOutOfBoundsException

或者,您也可以直接执行
+ 1

而不是 .mapToObj(i -> i + 1)

,而不是 
.boxed()
,这会产生相同的结果。
    

这是在即将推出的 Java 24 中使用

0
投票
windowSliding

收集器的解决方案,作为

Stream Gatherers
功能的一部分添加: Optional<Bean> match = list.reversed().stream() .gather(Gatherers.windowSliding(2)) .filter(l -> l.getLast().getText() == null) .map(List::getFirst) .findFirst();

这会在每对元素上流式传输列表的反向视图。 当遇到最后一个元素的文本为
null
的对时,将保留该对(请注意,这是向后的,因为列表是相反的)。 该对的第一个元素是原始列表中位于带有

null

 文本的元素之后的元素,因此保留该元素。  最后,通过
findFirst
使用第一个元素,其余元素被丢弃(由于短路而没有被处理)。
详细分解

// [(1,null),(2,"t2"),(3,null),(4,"t4"),(5,"t5")] List<Bean> list = List.of( new Bean(1, null), new Bean(2, "t2"), new Bean(3, null), new Bean(4, "t4"), new Bean(5, "t5") ); list // [(1,null),(2,"t2"),(3,null),(4,"t4"),(5,"t5")] .reversed() // [(5,"t5"),(4,"t4"),(3,null),(2,"t2"),(1,null)] .stream() // [(5,"t5"),(4,"t4"),(3,null),(2,"t2"),(1,null)] .gather(Gatherers.windowSliding(2)) // [[(5,"t5"),(4,"t4")],[(4,"t4"),(3,null)],[(3,null),(2,"t2")],[(2,"t2"),(1,null)]] .filter(l -> l.getLast().getText() == null) // [[(4,"t4"),(3,null)],[(2,"t2"),(1,null)]] .map(List::getFirst) // [(4,"t4"),(2,"t2")] .findFirst(); // (4,"t4")


© www.soinside.com 2019 - 2024. All rights reserved.