为了账号安全,请及时绑定邮箱和手机立即绑定

在这种情况下如何对列表进行流式排序?

在这种情况下如何对列表进行流式排序?

交互式爱情 2022-11-10 15:03:19
我在 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) }
查看完整描述

4 回答

?
慕森王

TA贡献1777条经验 获得超3个赞

你可以这样尝试:


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());


查看完整回答
反对 回复 2022-11-10
?
森栏

TA贡献1810条经验 获得超5个赞

您当然可以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())));


查看完整回答
反对 回复 2022-11-10
?
HUX布斯

TA贡献1876条经验 获得超6个赞

如果您已经有一个排序列表(按 降序generationTs),就像您在示例代码中那样,您可以使用 aHashSet和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]

如果您已经有一个排序列表,则此解决方案应该是最快的解决方案之一。


查看完整回答
反对 回复 2022-11-10
?
qq_遁去的一_1

TA贡献1725条经验 获得超7个赞

下面是一种方法。


将第一个时间戳分组,然后使用 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);

    }

}

}


查看完整回答
反对 回复 2022-11-10
  • 4 回答
  • 0 关注
  • 108 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信