Arhn - архитектура программирования

Группировка по двум свойствам и сопоставление с другим объектом

У меня есть следующие данные:

uuid    id1 id2 hId hName       percent golden
1       J   K   a   fetchflow   38%     34%
2       J   K   b   codelibs1   45%     34%
3       J   K   c   codelibs2   97%     34%
10      K   L   a   fetchflow   16%     10%
11      K   L   b   codelibs1   95%     10%
12      K   L   c   codelibs2   12%     10%
13      K   M   a   fetchflow   64%     14%
14      K   M   b   codelibs1   53%     14%
15      K   M   c   codelibs2   48%     14%

И хочу добраться до этого:

Compare To  Golden  a   b   c
J       K   34%     38% 45% 97%
K       L   10%     16% 95% 12%
K       M   14%     64% 53% 48%

Примечание. Pair(id1, id2) == Pair(id2, id1), поэтому они взаимозаменяемы.

Я хочу сохранить его в следующей структуре данных Java:

class Foo {
    int id1;
    int id2;
    double golden;
    /*
        [a -> 0.38,
        b -> 0.45,
        c -> 0.97]
    */
    Map<Integer, Double> comparisons;
}

В настоящее время у меня есть следующий код, но я не могу сопоставить его с нужной мне структурой данных:

comparisons
        .stream()
        .collect(
                groupingBy(
                        Function.identity(),
                        () -> new TreeMap<>(
                                Comparator.<ComparisonResultSet, Integer>comparing(o -> o.vacancy_id_1).thenComparing(o -> o.vacancy_id_2)
                        ),
                        collectingAndThen(
                                reducing((o, o2) -> o), Optional::get
                        )
                ));

  • Ваш компаратор не делает id1 и id2 взаимозаменяемыми. 11.11.2016
  • 1: Да, я заметил это. Я, вероятно, буду использовать взаимозаменяемый кортеж для id1 и id2. 2: new Foo(J, K, 0.34, [a=0.38; b=0.45; c=0.97]; new Foo(K, L, 0.1, [a=0.16; b=0.95; c=0.12]; new Foo(K, M, 0.14, [a=0.64; b=0.53; c=0.48] 11.11.2016

Ответы:


1

Одним из решений, или, скорее, отправной точкой, было бы

List<Foo> result = list.stream().collect(Collectors.collectingAndThen(
    Collectors.groupingBy(
            o -> Arrays.asList(o.vacancy_id_1, o.vacancy_id_2),
            Collectors.toMap(o -> o.hId, o -> Arrays.asList(o.percent, o.golden))),
    m -> m.entrySet().stream().map(e -> new Foo(
            e.getKey().get(0), e.getKey().get(1),
            e.getValue().values().stream().mapToDouble(l->l.get(1))
                    .reduce((a,b)->{assert a==b; return a; }).getAsDouble(),
            e.getValue().entrySet().stream()
                    .collect(Collectors.toMap(Map.Entry::getKey, en->en.getValue().get(0)))
    )).collect(Collectors.toList())
));

который использует только стандартные классы Collection, что усложняет ситуацию. Он группируется по Arrays.asList(o.vacancy_id_1, o.vacancy_id_2), что подразумевает упорядочение идентификаторов. Вы можете обернуть его new HashSet<>(…), чтобы получить независимый от порядка ключ, однако это усложняет решение, когда дело доходит до построения экземпляров Foo, поскольку требуются выделенные id1 и id2. т.е.

List<Foo> result = list.stream().collect(Collectors.collectingAndThen(
    Collectors.groupingBy(
            o -> new HashSet<>(Arrays.asList(o.vacancy_id_1, o.vacancy_id_2)),
            Collectors.toMap(o -> o.hId, o -> Arrays.asList(o.percent, o.golden))),
    m -> m.entrySet().stream().map(e -> {
        Iterator<Integer> it = e.getKey().iterator();
        return new Foo(
            it.next(), it.next(),
            e.getValue().values().stream().mapToDouble(l->l.get(1))
                    .reduce((a,b)->{assert a==b; return a; }).getAsDouble(),
            e.getValue().entrySet().stream()
                    .collect(Collectors.toMap(Map.Entry::getKey, en->en.getValue().get(0)))
        );
    }).collect(Collectors.toList())
));

Обратите внимание, что new HashSet<>(Arrays.asList(o.vacancy_id_1, o.vacancy_id_2)) можно заменить на Set.of(o.vacancy_id_1, o.vacancy_id_2) в Java 9.

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

Еще одним препятствием является «золотая» недвижимость. Без него нижестоящим сборщиком был бы Collectors.toMap(o -> o.hId, o -> o.percent), производящий в точности желаемую карту для результата Foo. Поскольку мы должны перенести сюда еще одно свойство, карта нуждается в последующем шаге преобразования после того, как «золотое» свойство будет уменьшено до одного значения.

Используя парный класс, например

public final class UnorderedPair<T> {
    public final T a, b;

    public UnorderedPair(T a, T b) {
        this.a = a;
        this.b = b;
    }
    public int hashCode() {
        return a.hashCode()+b.hashCode()+UnorderedPair.class.hashCode();
    }
    public boolean equals(Object obj) {
        if(this == obj) return true;
        if(!(obj instanceof UnorderedPair)) return false;
        final UnorderedPair<?> other = (UnorderedPair<?>) obj;
        return a.equals(other.a) && b.equals(other.b)
            || a.equals(other.b) && b.equals(other.a);
    }
}

и сборщик pairing из этого ответа, мы получаем

List<Foo> result = list.stream().collect(Collectors.collectingAndThen(
    Collectors.groupingBy(
        o -> new UnorderedPair<>(o.vacancy_id_1, o.vacancy_id_2),
            pairing(
                Collectors.toMap(o -> o.hId, o -> o.percent),
                Collectors.reducing(null, o -> o.golden,
                    (a,b) -> {assert a==null || a.doubleValue()==b; return b; }),
            (m,golden) -> new AbstractMap.SimpleImmutableEntry<>(m,golden))),
    m -> m.entrySet().stream().map(e -> new Foo(
        e.getKey().a, e.getKey().b, e.getValue().getValue(), e.getValue().getKey()))
    .collect(Collectors.toList())
));

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

11.11.2016
  • Внимание: по крайней мере, IntelliJ не может определить правильные типы во предпоследней строке .map(e -> ...., но код по-прежнему компилируется и работает правильно. 11.11.2016

  • 2

    Я принял во внимание, что id1 и id2 и золотой одинаковы, id1 и id2 взаимозаменяемы.

    Как насчет этого:

    list.stream().collect(Collectors.collectingAndThen(Collectors.groupingBy(struct -> {
            String first = struct.getId1();
            String second = struct.getId2();
    
            if (first.compareTo(second) > 0) {
                return ImmutableList.of(first, second, struct.getGolden());
            }
            return ImmutableList.of(second, first, struct.getGolden());
    
        }, Collectors.toMap(Structure::getHId, Structure::getPercentage)),
                elem -> elem.entrySet().stream().map(entry -> {
                    ImmutableList<?> values = entry.getKey();
                    return new Foo((String) values.get(0), (String) values.get(1), (Integer) values.get(2),
                            entry.getValue());
                }).collect(Collectors.toList())));
    

    Этот сменный ключ делает вещи немного уродливыми.

    11.11.2016
    Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..