Фильтрация объектов из списка, имеющих одинаковый член - PullRequest
0 голосов
/ 22 февраля 2019

У меня есть список объектов.Объект выглядит следующим образом:

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;
  ...
}

Мне нужно найти элементы, которые имеют одинаковые agendaCode, visitTypeCode и scheduledTime, и я не могу этого сделать для своей жизни.

Я попробовал это:

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, которые имеют одинаковые agendaCode, visitTypeCode и scheduledTime.Я борюсь с функциональным программированием, поэтому любая помощь или указатели были бы великолепны!

Это Java 11, и я также использую vavr.

Ответы [ 4 ]

0 голосов
/ 22 февраля 2019

Поля, по которым вы хотите сгруппировать, являются строками.Вы можете определить функцию, которая объединяет значения этих полей и использует ее в качестве ключа для ваших групп.Пример

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));
0 голосов
/ 22 февраля 2019

Мне нравится Идея Руслана использовать Collectors :: groupingBy .Тем не менее, мне не нравится создавать новый класс или определять новый метод equals.Оба они принуждают вас к единственной Collectors::groupingBy версии.Что если вы хотите сгруппировать по другим полям другими методами?

Вот фрагмент кода, который должен помочь вам решить эту проблему:

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

Моя идея заключалась в создании нового контейнера.для каждого необходимого поля (ndaCode, visitTypeCode, scheludedTime) и сравните слоты в этих вновь созданных контейнерахМне бы хотелось сделать это с простым Object массивом, но он не работает - массивы следует сравнивать с Arrays.equals, который не является методом сравнения, используемым Collectors::groupingBy.

Обратите внимание, чтоВы должны хранить где-нибудь или использовать метод, чтобы определить, по каким полям вы хотите группировать.

0 голосов
/ 22 февраля 2019

Поскольку вы упомянули, что используете vavr, вот способ решения этого вопроса с помощью vavr.

Предполагается, что у вас есть io.vavr.collection.List (или Array или Vector или Stream или аналогичныйvavr collection) посещений:

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()
            )
    )
);
0 голосов
/ 22 февраля 2019

Самый простой способ - определить новый класс с необходимыми полями (agendaCode, visitTypeCode и scheduledTime).Не забывайте о equals/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()));

Также вы можете просто реализовать метод equals внутри Visitsдля agendaCode, visitTypeCode и scheduledTime.В этом случае используйте groupingBy по s.getVisit()

...