Удалить объекты entrySet с повторяющимися значениями полей - PullRequest
0 голосов
/ 10 мая 2018

у меня есть Hashmap<String, List<A>>

В настоящее время я фильтрую все объекты из моего списка записей, которые имеют A.result null

map.entrySet().stream()
            .forEach(aList -> aList.getValue().removeIf(a -> a.result == null));

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

так что если бы у меня было A1.result = 1 и A2.result = 1, я бы просто получил один.

РЕДАКТИРОВАТЬ: Перемещено временное решение в качестве ответа, поскольку лучшего способа еще не найдено.

Ответы [ 5 ]

0 голосов
/ 12 мая 2018

Создать фабричный метод для предиката,

public static Predicate<A> nullOrDuplicate() {
    Set<Object> set = new HashSet<>();
    set.add(null);
    return a -> !set.add(a.result);
}

тогда вы можете выполнить операцию так же просто, как

Map<String, List<A>> map;
...
map.values().forEach(list -> list.removeIf(nullOrDuplicate()));
0 голосов
/ 11 мая 2018

Временное решение:

List<String> results= new ArrayList<>();    
map.entrySet().stream()
        .forEach(aList -> 
            aList.getValue().removeIf(a -> {
                if (a.result == null) {
                    return true;
                }
                if (results.stream().filter(result -> result.equalsIgnoreCase(a.result)).count() > 0) {
                    return true;
                }
                results.add(a.result);
                return false;
            }));
0 голосов
/ 10 мая 2018

Не очень элегантный, поскольку создает временные объекты (карты, списки)

actDwhResultMap.entrySet()
        .stream()
        .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue()
                .stream()
                .filter(a -> a.result != null)
                .collect(Collectors.collectingAndThen(Collectors
                                    .toMap(a -> a.result,
                                        java.util.function.Function.identity(),
                                        ((a1, a2) -> a1),
                                        LinkedHashMap::new),
                        result -> new ArrayList<>(result.values())))
        ));

Он перебирает записи карты и для каждого значения (List<A>) создает временную карту (LinkedHashMap для поддержания порядка вставки) с ключом A.result и, если существует два объекта с одинаковым result, выбирает первое один.

В конце (в функции, переданной в collectingAndThen), он возвращает значения в виде списка. Затем он вставляется в новую карту с ключом исходного элемента карты.

0 голосов
/ 10 мая 2018

Как сказал Хемант в их комментарии , было бы разумно переопределить Object#equals и Object#hashCode в A, чтобы два объекта можно было сравнить по их полю result:

@Override
public boolean equals(Object o) {
    if (!(o instanceof A)) {
        return false;
    }
    return Objects.equals(result, ((A) o).result);
}

@Override
public int hashCode() {
    return Objects.hash(result);
}

Теперь вы можете просто вспомнить свой Map на Map<String, Set<A>>, что можно сделать в Java 10 следующим образом:

map.entrySet()
   .stream()
   .collect(Collectors.toMap(Map.Entry::getKey, e -> Set.copyOf(e.getValue()))));

Это немного отличается в Java 8:

map.entrySet()
   .stream()
   .collect(Collectors.toMap(Map.Entry::getKey, e -> new HashSet<>(e.getValue())))
0 голосов
/ 10 мая 2018

Может быть, использовать Set для вашей задачи?Внутри forEach вы можете добавить инициализацию набора, а затем добавить туда свои значения.Когда вы вызываете метод add (), он возвращает false, если значение уже есть в наборе, поэтому вы его отфильтруете.Вот мой фрагмент, я использую Список, но вы можете заменить его своим классом А

public static void main(String[] args) {
    HashMap<String, List<Integer>> factDwhResultMap = new HashMap<>();
    factDwhResultMap.put("k1", new ArrayList<>(Arrays.asList(1,2,3,3,null)));
    factDwhResultMap.put("k2", new ArrayList<>(Arrays.asList(null,7,7,7,null)));

    factDwhResultMap.entrySet().stream().forEach(aList -> {
         Set resultSet = new HashSet();
         aList.getValue().removeIf(a -> a == null || !resultSet.add(a));
         System.out.println(aList);
         });
}

Выходные данные

k1=[1, 2, 3]
k2=[7]
...