如何用Java Stream实现按人员每日去重过滤嵌套TimeOffSlot列表?
问题分析
你的代码存在两个核心问题:
- 语法错误:第二个
filter方法的参数逻辑错误,slot.getPersonTimeOffList.stream().filter(distinctByKey(...))返回的是Stream对象,无法直接作为Predicate(需要返回boolean)传入外层filter,会直接编译失败。 - 逻辑偏差:需求是为每个人员保留当天的第一个/最早的TimeOffSlot,但原代码试图过滤Slot内部的人员列表,完全没触碰到“按人员去重并保留对应Slot”的核心逻辑。
解决方案
核心思路是:先拆分Slot与人员的关联关系,按人员分组后保留每个人员的首个Slot,最后去重重复的Slot(因为一个Slot可能对应多个人员)。
完整实现代码
// 第一步:过滤出当天的所有TimeOffSlot Collection<TimeOffSlot> todaySlots = timeOffSlots.stream() .filter(slot -> slot.getSlotDate().equals(LocalDate.now())) .collect(Collectors.toList()); // 第二步:按人员ID分组,为每个人员保留当天最早的TimeOffSlot Map<Long, TimeOffSlot> personToFirstSlot = todaySlots.stream() // 把每个Slot拆成【人员ID - Slot】的映射条目(一个Slot对应多个人则拆多条) .flatMap(slot -> slot.getPersonTimeOffList().stream() .map(personSlot -> new AbstractMap.SimpleEntry<>(personSlot.getPerson().getPersonId(), slot))) // 按人员ID分组,遇到同一人员的多个Slot时,保留时间更早的那个 .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (existingSlot, newSlot) -> existingSlot.getSlotTime().isBefore(newSlot.getSlotTime()) ? existingSlot : newSlot )); // 第三步:提取最终Slot列表,用LinkedHashSet去重(避免一个Slot被多个人员关联而重复出现) Collection<TimeOffSlot> filteredSlots = new ArrayList<>(new LinkedHashSet<>(personToFirstSlot.values()));
关键逻辑说明
- 拆分关联:用
flatMap把每个TimeOffSlot拆成多个「人员ID-Slot」对,解决一个Slot对应多个人的情况。 - 分组去重:
Collectors.toMap的第三个参数是合并规则,这里选择保留时间更早的Slot;如果只想保留列表中第一个出现的Slot,把合并规则改成(existing, newSlot) -> existing即可。 - 去重Slot:用
LinkedHashSet保证Slot的唯一性和顺序,避免同一个Slot因关联多个人员而重复出现在结果里。
内容的提问来源于stack exchange,提问作者bob82
相关产品推荐
相关产品推荐

