Java 在一组对象中查找字符串属性的连续序列(通过流API)
我必须编写一个方法,该方法采用Java 在一组对象中查找字符串属性的连续序列(通过流API),java,java-8,java-stream,Java,Java 8,Java Stream,我必须编写一个方法,该方法采用分类数据集和列表。它必须确定是否存在一个连续的MyEvent序列,该序列通过某个类属性表示给定的列表 让我们假设存在以下(代码-)情况: List<String> list = new ArrayList<String>() list.add("AAA"); list.add("BBB"); 该方法正在运行(至少对于这个2元素序列) 是否可以使用流API在单个调用中实现这一点(对于未知大小的序列)? 您的任务并不难,只需创建一个流,应用过滤
分类数据集
和列表
。它必须确定是否存在一个连续的MyEvent
序列,该序列通过某个类属性表示给定的列表
让我们假设存在以下(代码-)情况:
List<String> list = new ArrayList<String>()
list.add("AAA");
list.add("BBB");
该方法正在运行(至少对于这个2元素序列)
是否可以使用流API在单个调用中实现这一点(对于未知大小的序列)?
您的任务并不难,只需创建一个
流
,应用过滤器
,然后请求最大值。有一个障碍是我们需要谓词中的前一个元素,但我们已经掌握了源集合,它可以提供它
实际上,每个SortedSet
也是一个NavigableSet
,它提供了获取上一个元素的方法(如果有),但由于您的要求是支持SortedSet
输入,我们必须为SortedSet
不是NavigableSet
的理论案例提供一个退步
然后,该操作可以实现为
public static MyEvent getMostRecentLastEventOfSequence(
SortedSet<MyEvent> events, List<String> sequence) {
String first = sequence.get(0), second = sequence.get(1);
UnaryOperator<MyEvent> previous;
if (events instanceof NavigableSet) {
NavigableSet<MyEvent> navigableSet = (NavigableSet<MyEvent>) events;
previous = navigableSet::lower;
}
else previous = event -> events.headSet(event).last();
return events.stream()
.filter(event -> event.getAbbreviation().equals(second))
.filter(event -> {
MyEvent p = previous.apply(event);
return p != null && p.getAbbreviation().equals(first);
})
.max(Comparator.naturalOrder()).orElse(null);
}
因此,此方法将向后搜索并在第一个匹配处停止,该匹配已是最大元素,而无需遍历所有元素。另一种解决方案是使用索引。序列的大小将不限于2
public static MyEvent getMostRecentLastEventOfSequence(SortedSet<MyEvent> events, List<String> sequence) {
final List<MyEvent> eventList = new ArrayList<>(events);
Collections.reverse(eventList);
final int seqLength = sequence.size();
OptionalInt first = IntStream.range(0, eventList.size() - seqLength + 1)
.filter(i -> IntStream.range(0, seqLength)
.allMatch(j -> eventList.get(i + j).getAbbreviation().equals(sequence.get(seqLength - j - 1))))
.findFirst();
return first.isPresent() ? eventList.get(first.getAsInt()) : null;
}
有时,最小化成为回答问题的首要要求。我想这就是其中之一,你完全可以摆脱所有的声明和初始化,直接进入业务逻辑,只需要最少的实体细节和测试输入。@Naman好的,我已经这么想了,但我不想回答很多反问题,比如
MyEvent
看起来怎么样等等。。。好的,我将尝试缩短这个问题。IntStream.range(0,events.size()-1).forEach(I->{MyEvent b=events.get(I+1);List temp=Arrays.asList(events.get(I.缩写,b.缩写);if(temp.equals(sequence)){possibleReturnValues.add(b);})
@HadiJ虽然你的代码看起来很有前途,但我无法返回它,因为它是一个void
操作,我需要返回MyEvent
的实例。此外,events
是一个SortedSet
,这意味着我无法访问索引。很抱歉,这两个事实加上没有任何解释,使您的代码对我来说毫无用处。无论如何,谢谢你……你不需要归还任何东西。只需使用我的代码而不是你的代码,代码的其他部分是不需要修改的。此外,在我看来,您可以对循环使用,为了获得更好的性能,还可以添加其他条件<代码>for(int i=0;i
非常感谢您的解释和这两种方法。我可以假设不可能使用单行或单语句流api调用吗?我期待着,但我认为这是可能的。NavigableSet
是一个非常有用的提示,因为我可以在应用该方法之前将元素存储在这样一个集合中。如上所述,大多数SortedSet
实现已经是NavigableSet
。这包括典型的实现,如TreeSet
和TreeMap
的键集。该操作实际上是一个单流语句。为了可读性和避免重复执行sequence.get(0)
和sequence.get(1)
,我只提取了first
和second
。类似地,测试集合是否为NavigableSet
也可以在函数本身内部完成,但这不会增加可读性和性能。抛开这些准备工作不谈,最后只有一个流操作。好的,谢谢,这回答了所有问题(并对我对单流操作的理解提出了一些问题)。这就是我想要的。您可以这样看:在第二个示例中,findFirst()
是唯一进行实际数据处理的方法调用。
public static MyEvent getMostRecentLastEventOfSequence(
SortedSet<MyEvent> events, List<String> sequence) {
String first = sequence.get(0), second = sequence.get(1);
UnaryOperator<MyEvent> previous;
if (events instanceof NavigableSet) {
NavigableSet<MyEvent> navigableSet = (NavigableSet<MyEvent>) events;
previous = navigableSet::lower;
}
else previous = event -> events.headSet(event).last();
return events.stream()
.filter(event -> event.getAbbreviation().equals(second))
.filter(event -> {
MyEvent p = previous.apply(event);
return p != null && p.getAbbreviation().equals(first);
})
.max(Comparator.naturalOrder()).orElse(null);
}
public static MyEvent getMostRecentLastEventOfSequence(
SortedSet<MyEvent> events, List<String> sequence) {
String first = sequence.get(0), second = sequence.get(1);
UnaryOperator<MyEvent> previous;
Stream<MyEvent> stream;
if (events instanceof NavigableSet) {
NavigableSet<MyEvent> navigableSet = (NavigableSet<MyEvent>) events;
previous = navigableSet::lower;
stream = navigableSet.descendingSet().stream();
}
else {
previous = event -> events.headSet(event).last();
stream = Stream.iterate(events.last(), previous).limit(events.size());
}
return stream
.filter(event -> event.getAbbreviation().equals(second))
.filter(event -> {
MyEvent p = previous.apply(event);
return p != null && p.getAbbreviation().equals(first);
})
.findFirst().orElse(null);
}
public static MyEvent getMostRecentLastEventOfSequence(SortedSet<MyEvent> events, List<String> sequence) {
final List<MyEvent> eventList = new ArrayList<>(events);
Collections.reverse(eventList);
final int seqLength = sequence.size();
OptionalInt first = IntStream.range(0, eventList.size() - seqLength + 1)
.filter(i -> IntStream.range(0, seqLength)
.allMatch(j -> eventList.get(i + j).getAbbreviation().equals(sequence.get(seqLength - j - 1))))
.findFirst();
return first.isPresent() ? eventList.get(first.getAsInt()) : null;
}
@Test
void test_56005015() throws Exception {
List<String> sequence = Arrays.asList("AAA", "BBB", "CCC");
SortedSet<MyEvent> events = new TreeSet<>();
events.add(new MyEvent("AAA", LocalDateTime.now().plusDays(1)));
events.add(new MyEvent("BBB", LocalDateTime.now().plusDays(2)));
events.add(new MyEvent("CCC", LocalDateTime.now().plusDays(3)));
events.add(new MyEvent("AAA", LocalDateTime.now().plusDays(4)));
events.add(new MyEvent("BBB", LocalDateTime.now().plusDays(5)));
events.add(new MyEvent("CCC", LocalDateTime.now().plusDays(6)));
MyEvent result = getMostRecentLastEventOfSequence(events, sequence);
System.out.println(result);
}
@Getter
@Setter
@AllArgsConstructor
@ToString
public static class MyEvent implements Comparable<MyEvent> {
private String abbreviation;
private LocalDateTime eventTime;
@Override
public int compareTo(MyEvent o) {
return eventTime.compareTo(o.eventTime);
}
}