Java 8: Как элегантно удалить избыточные внешние объекты на основе внутреннего идентификатора объекта и даты в Java 8? - PullRequest
0 голосов
/ 07 июня 2018

Существует ObjectOuter, который содержит другой объект с именем ObjectInner, имеющий идентификатор.Нам нужно удалить Redundant ObjectOuter с дублирующимися идентификаторами ObjectInner.(У нас есть другой объект DateFinish на рисунке)

public static List<ObjectOuter> removeRedundantObject(List<ObjectOuter> ObjectOuterOriginal){
      if(ObjectOuterOriginal.size() == 1) {
         return ObjectOuterOriginal;
      }
      List<ObjectInner> allObjectInner = ObjectOuterOriginal.stream().map(ObjectOuter::getObjectInner).collect(toList());
      List<Long> allObjectInnerIds = allObjectInner.stream().map(ObjectInner::getObjectInnerId).collect(toList());
      List<ObjectOuter> myFinalObjectOuter = new ArrayList<>();
      if(ObjectOuterOriginal.size() == allObjectInnerIds.stream().distinct().collect(Collectors.toList()).size()){
         return ObjectOuterOriginal;
      }
      Set<Long> duplicateObjectOuter = CommonUtils.getDuplicateNumbers(allObjectInnerIds); //Returns numbers which are duplicate in set
      if(SetUtils.emptyIfNull(duplicateObjectOuter).isEmpty()){
        return ObjectOuterOriginal;
      } else {
        duplicateObjectOuter.forEach((objectInnerId) -> {
              List<ObjectOuter> myOwnObjectOuter = ObjectOuterOriginal.stream().filter(d -> d.getObjectInner().getObjectInnerId().equals(objectInnerId) && d.getDateFinish()==null).collect(Collectors.toList());
              if(ListUtils.emptyIfNull(myOwnObjectOuter).isEmpty()) {
                  LocalDate maxDate = ObjectOuterOriginal.stream().filter(d -> d.getObjectInner().getObjectInnerId().equals(objectInnerId) && d.getDateFinish()!=null).map(u -> u.getDateFinish()).max(LocalDate::compareTo).get();
                  List<ObjectOuter> ownObjectOuter = ObjectOuterOriginal.stream().filter(d -> d.getObjectInner().getObjectInnerId().equals(objectInnerId) && d.getDateFinish()!=null).filter(d -> d.getDateFinish().compareTo(maxDate) == 0).collect(toList());
                  myFinalObjectOuter.addAll(ownObjectOuter);
              } else {
                  myFinalObjectOuter.addAll(myOwnObjectOuter);
              }
        });
        duplicateObjectOuter.forEach((objectInnerId) -> {
            ObjectOuterOriginal.removeIf(d -> d.getObjectInner().getObjectInnerId().compareTo(objectInnerId) == 0);
        });
        ObjectOuterOriginal.addAll(myFinalObjectOuter);
      }
      return ObjectOuterOriginal;
  }

Также нам нужно использовать фильтр на innerObject, чтобы выбрать только те идентификаторы, у которых дата равна NULL или имеет максимальную дату среди дублирующихся элементов;где дата находится во внешнем объекте.

Выше код выполняется правильно, но в Java 8 рекомендуется обрабатывать его более элегантно. Я могу только думать об опущении первого оператора if.но есть ли возможность слияния операторов в Java-8 для приведенного выше фрагмента?

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

Если ваши идентификаторы уже уникальны, вы можете просто сделать:

public static void main(String[] args) {
    Outer[] outers = {
            new Outer(new Inner("a")),
            new Outer(new Inner("b")),
            new Outer(new Inner("c")),
            new Outer(new Inner("a")),
            new Outer(new Inner("b")),
            new Outer(new Inner("c")),
    };

    Map<String, Outer> OutersById = Arrays.stream(outers).collect(Collectors.toMap(outer -> outer.inner.id, outer -> outer));

    OutersById.forEach((k,v)->System.out.println(k+", "+v));
}

Но это приведет к исключению Duplicate Key.

Чтобы управлять своими дубликатами и использовать собственную стратегию устранения неоднозначности,

Map<String, Outer> OutersById = Arrays.stream(outers).collect(Collectors.toMap(outer -> outer.inner.id, outer -> outer));

Можно изменить на

Map<String, Outer> OutersById = Arrays.stream(outers)
                .collect(
                        Collectors.toMap(
                                outer -> outer.inner.id, 
                                outer -> outer,
                                (a, b) -> a.hashCode() > b.hashCode() ? a : b
                                ));

Или любую другую стратегию, которую вы хотите, возможноНа External есть дата, которую можно сравнить?

Может быть, a и b можно объединить в новый объект ab?

Обновление:

public static void main(String[] args) {
        Instant now = Instant.now();
        Instant nxtWeek= now.plus(Duration.ofDays(7));

        Outer[] outers = {
                new Outer(new Inner("a"), null),
                new Outer(new Inner("b"), Date.from(now)),
                new Outer(new Inner("c"), Date.from(nxtWeek)),

                new Outer(new Inner("a"), Date.from(now)),
                new Outer(new Inner("b"), Date.from(nxtWeek)),
                new Outer(new Inner("c"), null),

        };

        Comparator<Outer> outerRanker = Comparator.comparing(Outer::getFinishDate, Comparator.nullsLast(Date::compareTo));

        Map<String, Outer> OutersById = Arrays.stream(outers)
                .collect(
                        Collectors.toMap(
                                outer -> outer.inner.id,
                                outer -> outer,
                                (a, b) -> outerRanker.compare(a,b) > 0 ? a : b
                                ));
        System.out.println("today: "+Date.from(now));
        OutersById.forEach((k,v)->System.out.println(k+", "+v));
    }

Результаты в

today: Thu Jun 07 15:11:12 ACST 2018
a, Outer{inner=Inner{id='a'}, FinishDate=null}
b, Outer{inner=Inner{id='b'}, FinishDate=Thu Jun 14 15:11:12 ACST 2018}
c, Outer{inner=Inner{id='c'}, FinishDate=null}

Process finished with exit code 0
0 голосов
/ 07 июня 2018

Вы можете просто использовать метод фильтра потока.

Set<Long> ids = new HashSet<>();

// Note: add returns true if element was not in the set
// so first occurrence will pass through filter,
// subsequent duplicates will be filtered out. 
return ObjectOuterOriginal.stream()
    .filter( o -> ids.add(o.getObjectInner().getObjectInnerId()) )
    .collect( Collections.toList() );

Да, это операция с состоянием в вызове фильтра, поэтому она, вероятно, считается «плохой формой», но она выполняет свою работу, является короткой, простой, быстрой и понятной.

...