我有一个带有两个timeStamp的Java对象列表,例如:
Obj(TimeStamp ts,TimeStamp generationTs,int值)。
最后,我不希望列表中的两个项目具有相同的ts。如果有的话,我只想保留最新一代的T。
实际上,我有该代码,它可以工作,但是我想知道如果使用流,我还能做得更好吗?
list.sort(Collections.reverseOrder());
List<Obj> returnedList = Lists.newArrayList();
if (!list.isEmpty()) {
returnedList.add(list.get(0));
Iterator<Obj> i = list.iterator();
while (i.hasNext()) {
Obj lastObj = returnedList.get(returnedList.size() - 1);
Obj nextObj = i.next();
if (!lastObj.getTs().isEqual(nextObj.getTs())) {
returnedList.add(nextObj);
} else {
if (lastObj.getGenerationTs().isBefore(nextObj.getGenerationTs())) {
returnedList.remove(lastObj);
returnedList.add(nextObj);
}
}
}
}
如果列表为:
{("2019-05-02T09:00:00Z", "2019-05-02T21:00:00Z", 1),
("2019-05-02T09:30:00Z", "2019-05-02T21:00:00Z", 2),
("2019-05-02T10:00:00Z", "2019-05-02T21:00:00Z", 3),
("2019-05-02T10:30:00Z", "2019-05-02T21:00:00Z", 4),
("2019-05-02T09:30:00Z", "2019-05-02T22:00:00Z", 5),
("2019-05-02T10:00:00Z", "2019-05-02T22:00:00Z", 6) }
它必须返回:
{("2019-05-02T09:00:00Z", "2019-05-02T21:00:00Z", 1),
("2019-05-02T09:30:00Z", "2019-05-02T22:00:00Z", 5),
("2019-05-02T10:00:00Z", "2019-05-02T22:00:00Z", 6)
("2019-05-02T10:30:00Z", "2019-05-02T21:00:00Z", 4) }
答案 0 :(得分:1)
您当然可以使用Stream
使用地图收集器,然后获取值
Collection<Obj> objects = list.stream()
.collect(Collectors.toMap(Obj::getTimeStamp,
Function.identity(),
(o1, o2) -> o1.getGenerationTs().isBefore(o2.getGenerationTs()) ? o2 : o1))
.values();
List<Obj> listOfObjects = new ArrayList<>(objects);
或更短:
List<Obj> result = list.stream()
.collect(Collectors.collectingAndThen(
Collectors.toMap(Obj::getTimeStamp,
Function.identity(),
(o1, o2) -> o1.getGenerationTs().isBefore(o2.getGenerationTs()) ? o2 : o1),
m -> new ArrayList<>(m.values())));
答案 1 :(得分:1)
您可以尝试这样:
Map<TimeStamp, Optional<Obj>> result =
list.stream().collect(Collectors.groupingBy(
Obj::getTs,
Collectors.maxBy(Comparator.comparing(Obj::getGenerationTs))
));
如@Naman在评论中所述的更多完整选项:
list.stream().collect(Collectors.groupingBy(
Obj::getTs,
Collectors.maxBy(Comparator.comparing(Obj::getGenerationTs))
)).values().stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
答案 2 :(得分:0)
以下是一种实现方法。
将第一个时间戳分组,然后使用maxBy查找具有最新一代时间戳的对象。最后,在第一个时间戳上进行排序并打印出来。
maxBy会生成Optional的事实有点难看,但是我找不到避免它的方法。
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.maxBy;
import java.time.Instant;
import java.util.Optional;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
public class SortTest {
@Test
public void t() {
final Stream<Obj> s = Stream.of(new Obj("2019-05-02T09:00:00Z", "2019-05-02T21:00:00Z", 1),
new Obj("2019-05-02T09:30:00Z", "2019-05-02T21:00:00Z", 2),
new Obj("2019-05-02T10:00:00Z", "2019-05-02T21:00:00Z", 3),
new Obj("2019-05-02T10:30:00Z", "2019-05-02T21:00:00Z", 4),
new Obj("2019-05-02T09:30:00Z", "2019-05-02T22:00:00Z", 5),
new Obj("2019-05-02T10:00:00Z", "2019-05-02T22:00:00Z", 6));
s.collect(groupingBy(o -> o.ts, maxBy((o1, o2) -> o1.generationTs.compareTo(o2.generationTs))))
.values()
.stream()
.map(Optional::get)
.sorted((o1, o2) -> o1.ts.compareTo(o2.ts))
.forEach(System.out::println);
}
private class Obj {
Instant ts;
Instant generationTs;
int i;
Obj(final String ts, final String generationTs, final int i) {
this.ts = Instant.parse(ts);
this.generationTs = Instant.parse(generationTs);
this.i = i;
}
@Override
public String toString() {
return String.format("%s %s %d", ts, generationTs, i);
}
}
}
答案 3 :(得分:0)
如果您已经有一个排序列表(以generationTs
降序),就像示例代码中的列表一样,则可以使用HashSet
和Collection.removeIf()
从中删除所有重复的时间戳列表:
list.sort(Comparator.comparing(Obj::getTs)
.thenComparing(Comparator.comparing(Obj::getGenerationTs)
.reversed()));
Set<Timestamp> keys = new HashSet<>();
list.removeIf(o -> !keys.add(o.getTs()));
使用此解决方案,您不必创建新列表,只需修改现有列表即可。该集合将要维护的所有密钥存储在列表中。由于该列表已排序,因此最新对象将保留在列表中,而其他值将被删除。
与您共享的数据的结果将是:
Obj[ts=2019-05-02T09:00:00Z, generationTs=2019-05-02T21:00:00Z, value=1]
Obj[ts=2019-05-02T09:30:00Z, generationTs=2019-05-02T22:00:00Z, value=5]
Obj[ts=2019-05-02T10:00:00Z, generationTs=2019-05-02T22:00:00Z, value=6]
Obj[ts=2019-05-02T10:30:00Z, generationTs=2019-05-02T21:00:00Z, value=4]
如果您已经有一个排序列表,则此解决方案应该是最快的解决方案之一。