【问题标题】:Set created from complex List从复杂列表创建的集合
【发布时间】:2018-01-31 05:18:26
【问题描述】:

所以我有一个列表,其中包含来自数据库的重复实体,具有相同的“Id”(它不是真正的 Id,而是一种),但 CreatedDate 不同。

所以我想从具有最新 CreatedDate 的重复项中获取最新实体。

例如,我有一个已创建用户的列表:

RealId|CreatedDate|Id|Name
1|20170101|1|User1
2|20170102|1|User1Modified
3|20170103|2|User2
4|20170104|2|User2Modified

从该列表中获得的最佳方式是什么:

RealId|CreatedDate|Id|Name
2|20170102|1|User1Modified
4|20170104|2|User2Modified

这是我的第一个想法

List<T> r = query.getResultList();

Set<T> distinct = r.stream().filter(x -> {
    List<T> clones = r.stream()
        .filter(y -> y.getId() == x.getId())
        .collect(Collectors.toList());

    T max = clones.stream()
        .max(Comparator.comparing(AbstractEntityHistory::getEntryDate))
        .get();

    return max.getNumber() == x.getNumber();
}).collect(Collectors.toSet());

我的另一个想法是让它按日期降序排列,然后像 distinct().collect() 一样:

Set<T> distinct2 = r.stream().sorted((x,y) -> {
   if(x.getEntryDate().isBefore(y.getEntryDate())) {
        return 1;
    } else if(x.getEntryDate().isAfter(y.getEntryDate())) {
        return -1;
    } else {
        return 0;
    }
}).distinct().collect(Collectors.toSet());

这里,T 覆盖了 equals,如果它们相等则监视 RealId,否则使用反射来监视所有其他字段。

【问题讨论】:

  • 我们不能修改sql查询吗?
  • 是的,我可以更改查询!我正在使用 Hibernate,所以我想我可以进行不选择重复项的查询

标签: java list set


【解决方案1】:

试试这个:

List<YourObject> collect = activities
              .stream()
              .collect(Collectors.groupingBy(
                        YourObject::getId, 
                        Collectors.maxBy(Comparator.comparing(YourObject::getCreatedDate))))
              .entrySet()
              .stream()
              .map(e -> e.getValue().get())
              .collect(Collectors.toList());

这里使用Collectors.groupingBy 创建Map&lt;Integer, Optional&lt;YourObject&gt;&gt;,按id 和最近的createDate 分组。您获得此地图的entrySet 并将其收集到List

【讨论】:

  • 你能解释一下你的方法吗?这将比 仅代码 答案更有帮助。
  • 使用 Hibernate 和 H2 嵌入式数据库,“getAll”然后使用您的方法或进行查询会更好吗?
  • @baskwo - 这是你getAll实体时的实现
  • @SchiduLuca 是的,我明白 :) 但我想知道将其作为查询是否会更好更快。因为 H2 嵌入式数据库受到硬盘驱动器速度的限制,所以我想知道通过执行相同操作的查询是否会更快,从而减少从硬盘驱动器的读取。
  • @SchiduLuca 不确定编辑是否到位...但是 1)请编辑代码以使其更具可读性 2)您可以静态导入以下方法需要 - 使代码更短 3) 因为您只需要 values,所以您可以在结果地图上调用 values,而不是 entrySet 4) 您直接在 可能 上调用 get缺少值,您可以先filter 缺少的Optionals。否则一加
【解决方案2】:

没有java8功能的东西:

    Map<Long, Item> map = new HashMap<>();
    for (Item item: items) {
        Item old = map.get(item.getId());
        if (old == null || old.getDate().before(item.getDate())) {
            map.put(item.getId(), item);
        }
    }

    List<Item> result = new ArrayList<Item>(map.values());

【讨论】:

    猜你喜欢
    • 2018-07-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-17
    • 1970-01-01
    • 1970-01-01
    • 2014-08-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多