我正在练习一些入门级的java 8 lambda功能。
给出一个消息列表,每个消息都包含一个消息偏移量,其中所有偏移必须形成一个连续的整数列表,我试图找出需要警告的空白。我觉得这一切都应该与一个漂亮的羔羊做得很好。但我不能把头绕着它。
所以,这里有一个工作片段:
private void warnAboutMessageGaps(final List<Message> messages) {
final List<Long> offsets = messages.stream()
.sorted(comparingLong(Message::getOffset))
.map(Message::getOffset)
.collect(toList())
;
for (int i = 0; i < offsets.size() - 1; i++) {
final long currentOffset = offsets.get(i);
final long expectedNextOffset = offsets.get(i) + 1;
final long actualNextOffset = offsets.get(i + 1);
if (currentOffset != expectedNextOffset) {
LOG.error("Missing offset(s) found in messages: missing from {} to {}", currentOffset + 1, actualNextOffset - 1);
}
}
}我无法理解的是如何使它能够在lambda中完成“与前一个/下一个对象的比较”。如有任何指示,将不胜感激。
/edit:关于StreamEx和其他第三方解决方案的建议,虽然受到赞赏,但不是我想要的。
发布于 2019-10-26 07:20:41
对于目前的问题,这种方法似乎更合适。
messages.stream().sorted( Comparator.comparingLong( Message::getOffset ) )
.reduce( (m1, m2) -> {
if( m1.getOffset() + 1 != m2.getOffset() )
LOG.error( "Missing offset(s) found in messages: missing from {} to {}", m1.getOffset(), m2.getOffset() );
return( m2 );
} );这个解决方案使用的是reduce,而不是它的预期用途。它仅使用reduce的能力来遍历流中的所有对。
reduce的结果是使用而不是。(不可能进一步使用结果,因为这将需要可变的减少。)
发布于 2017-03-15 13:47:44
您可以使用StreamEx使用pairMap方法来完成这一任务:
StreamEx.of(messages)
.sorted(Comparator.comparingLong(Message::getOffset))
.pairMap((prev, next) -> new Message[] {prev, next})
.forEach(prevNext -> {
long currentOffset = prevNext[0].getOffset();
long expectedNextOffset = prevNext[0].getOffset() + 1;
long actualNextOffset = prevNext[1].getOffset();
if (currentOffset != expectedNextOffset) {
LOG.error(
"Missing offset(s) found in messages: missing from {} to {}",
currentOffset + 1, actualNextOffset - 1);
}
});发布于 2017-03-16 13:01:47
有时候,尝试使用lambda表达式做任何事情都会使解决方案更加复杂。您可以使用:
messages.stream()
.mapToLong(Message::getOffset)
.sorted()
.forEachOrdered(new LongConsumer() {
boolean first=true;
long expected;
public void accept(long value) {
if(first) first=false;
else if(value!=expected)
LOG.error("Missing offset(s) found in messages: missing from {} to {}",
expected, value);
expected=value+1;
}
});但是请注意,无论流链看起来多么流畅,sorted()是一个有状态的中间操作,它在幕后创建和使用支持数组。如果显式地使用该数组,则不会丢失任何内容:
long[] l = messages.stream().mapToLong(Message::getOffset).toArray();
Arrays.sort(l);
for(int ix=1; ix<l.length; ix++) {
long value = l[ix], expected = l[ix-1]+1;
if(value!=expected)
LOG.error("Missing offset(s) found in messages: missing from {} to {}",
expected, value);
}很难找到更简单的解决办法。但是,如果要减少所需的内存量,可以使用BitSet而不是数组:
OptionalLong optMin = messages.stream().mapToLong(Message::getOffset).min();
if(!optMin.isPresent()) return;
long min = optMin.getAsLong();
BitSet bset = messages.stream()
.mapToLong(Message::getOffset)
.collect(BitSet::new, (bs,l) -> bs.set((int)(l-min)), BitSet::or);
for(int set=0, clear; set>=0; ) {
clear = bset.nextClearBit(set);
set = bset.nextSetBit(clear);
if(set >= 0)
LOG.error("Missing offset(s) found in messages: missing from {} to {}",
min+clear, min+set);
}与偏移值范围相比,如果没有空白或相当小的空白,这将大大减少使用的内存。当最小偏移距和最大偏移量之间的距离大于Integer.MAX_VALUE时,就会失败。
你可能会事先检查一下,如果根本没有漏洞的话,这也会为你提供捷径的机会:
LongSummaryStatistics stat = messages.stream()
.mapToLong(Message::getOffset).summaryStatistics();
if(stat.getCount()==0 ||
// all solutions assume that there are no duplicates, in this case,
// the following test allows to prove that there are no gaps:
stat.getMax()-stat.getMin()==messages.size()-1) {
return;
}
if(stat.getMax()-stat.getMin()>Integer.MAX_VALUE) {
// proceed with array based test
…
}
else {
long min = stat.getMin();
// proceed with BitSet based test
…https://stackoverflow.com/questions/42811045
复制相似问题