从列表中筛选具有相同成员的对象

Filter objects from a list that have the same member

提问人:coconut 提问时间:2/22/2019 最后编辑:Mikhail Kholodkovcoconut 更新时间:2/23/2019 访问量:579

问:

我有一个对象列表。该对象如下所示:

public class Slots {
  String slotType;
  Visits visit;
}


public class Visits {
  private long visitCode;
  private String agendaCode;
  private String scheduledTime;
  private String resourceType;
  private String resourceDescription;
  private String visitTypeCode;
  ...
}

我需要找到具有相同元素的元素,而对于我来说,我无法完成它。agendaCodevisitTypeCodescheduledTime

我试过了这个:

Set<String> agendas = slotsResponse.getContent().stream()
    .map(Slots::getVisit)
    .map(Visits::getAgendaCode)
    .collect(Collectors.toUnmodifiableSet());

Set<String> visitTypeCode = slotsResponse.getContent().stream()
    .map(Slots::getVisit)
    .map(Visits::getVisitTypeCode)
    .collect(Collectors.toUnmodifiableSet());

Set<String> scheduledTime = slotsResponse.getContent().stream()
    .map(Slots::getVisit)
    .map(Visits::getScheduledTime)
    .collect(Collectors.toUnmodifiableSet());

List<Slots> collect = slotsResponse.getContent().stream()
    .filter(c -> agendas.contains(c.getVisit().getAgendaCode()))
    .filter(c -> visitTypeCode.contains(c.getVisit().getVisitTypeCode()))
    .filter(c -> scheduledTime.contains(c.getVisit().getScheduledTime()))
    .collect(Collectors.toList());

但它并没有像我想象的那样做。理想情况下,我会有一个列表列表,其中每个子列表都是共享相同 和 的 Slots 对象列表。我在函数式编程方面很挣扎,所以任何帮助或指导都会很棒!agendaCodevisitTypeCodescheduledTime

这是 Java 11,我也在使用 vavr。

Java 函数式编程 java-stream vavr

评论

0赞 Naman 2/22/2019
你可以看看这个答案中的逻辑,我相信这就是解决你要做的事情的方法。filter

答:

1赞 Ruslan 2/22/2019 #1

最简单的方法是定义一个包含必需品字段 (和 ) 的新类。别忘了.agendaCodevisitTypeCodescheduledTimeequals/hashcode

public class Visits {
    private long visitCode;
    private String resourceType;
    private String resourceDescription;
    private Code code;
    ...
}
class Code {
    private String agendaCode;
    private String scheduledTime;
    private String visitTypeCode;
    ...
    @Override
    public boolean equals(Object o) {...}
    @Override
    public int hashCode() {...}
}

然后,您可以使用以下内容:groupingBy

Map<Code, List<Slots>> map = slotsResponse.getContent().stream()
            .collect(Collectors.groupingBy(s -> s.getVisit().getCode()));

此外,您只能在 和 中实现方法。在本例中,请使用equalsVisitsagendaCodevisitTypeCodescheduledTimegroupingBys.getVisit()

1赞 Abrikot 2/22/2019 #2

我喜欢 Ruslan 使用 Collectors::groupingBy 的想法。尽管如此,我不喜欢创建一个新类或定义一个新方法。他们俩都强迫你使用一个版本。如果要在其他方法中按其他字段进行分组怎么办?equalsCollectors::groupingBy

下面是一段代码,可以让你克服这个问题:

slotsResponse.getContent()
    .stream()
    .collect(Collectors.groupingBy(s -> Arrays.asList(s.getVisit().getAgendaCode(), s.getVisit().getVisitTypeCode(), s.getVisit().getScheduledTime())))
    .values();

我的想法是为每个需要的字段(agendaCode、visitTypeCode、scheludedTime)创建一个新容器,并比较这些新创建的容器上的插槽。我本来想用一个简单的数组来做到这一点,但它不起作用 - 数组应该与 Arrays.equals 进行比较,这不是 .ObjectCollectors::groupingBy

请注意,您应该存储在某个位置或使用一种方法来定义要按哪些字段进行分组。

3赞 Nándor Előd Fekete 2/22/2019 #3

既然你提到你正在使用 vavr,这里是解决这个问题的 vavr 方法。

假设您有(或或类似的 vavr 集合)访问:io.vavr.collection.ListArrayVectorStream

List<Visits> visits = ...;

final Map<Tuple3<String, String, String>, List<Visits>> grouped =
    visits.groupBy(visit ->
        Tuple.of(
            visit.getAgendaCode(),
            visit.getVisitTypeCode(),
            visit.getScheduledTime()
        )
    );

或者通过访问:java.util.List

List<Visits> visits = ...;

Map<Tuple3<String, String, String>, List<Visits>> grouped = visits.stream().collect(
    Collectors.groupingBy(
        visit ->
            Tuple.of(
                visit.getAgendaCode(),
                visit.getVisitTypeCode(),
                visit.getScheduledTime()
            )
    )
);
1赞 Eritrean 2/22/2019 #4

要作为分组依据的字段都是字符串。您可以定义一个函数来连接这些字段值,并将其用作组的键。例

Function<Slots,String> myFunc = s -> s.getVisit().agendaCode + s.getVisit().visitTypeCode + s.getVisit().scheduledTime;
                               // or s.getVisit().agendaCode +"-"+ s..getVisit().visitTypeCode +"-"+ s.getVisit().scheduledTime;

然后按如下方式分组:

Map<String,List<Slots>> result = slotsResponse.getContent().stream()
                               .collect(Collectors.groupingBy(myFunc));

评论

1赞 Naman 2/22/2019
语法似乎无效,可能只想在编译器上尝试一下,输出将是映射到键的单个条目,该条目基于与提取 .但恕我直言,这种方法很好。myFuncList<Slots>
1赞 Naman 2/23/2019
我的意思是—— 1.字段是 的一部分,而不是 函数定义的一部分,因此需要更新函数定义以使其编译。2.在地图上查找时,必须执行相同的逻辑才能形成正确的查找键。() < -- 尽管如果知道的话,这应该适用。VisitsSlotsresults.agendaCode + s.visitTypeCode + s.scheduledTimeresult.getmyFuncSlot
1赞 Nándor Előd Fekete 2/23/2019
此外,x=a+b+c=d+e+f 它们将被分组到同一组中,同时对各个组件具有不同的值。所以串联不能保证是正确的。