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

Транспонировать мультикарту в список карт

Предположим, у меня есть такая мультикарта:

MiddleName -> null
EmailAddress -> [email protected], [email protected], [email protected]
FirstName -> Toni, Mary, Paul
LastName -> Barry, null ,White
Id -> null

Обратите внимание, что каждая запись «значения» может быть полностью пустой или содержать то же количество значений, что и запись с большим количеством записей (я не знаю, какая именно), даже если некоторые из них равны нулю.

Я хочу, чтобы он «переносил» его в список карт, например:

MiddleName -> null
EmailAddress -> [email protected]
FirstName -> Toni
LastName -> Barry
Id -> null

MiddleName -> null
EmailAddress -> Mary@hermail
FirstName -> John
LastName -> null
Id -> null

MiddleName -> null
EmailAddress -> [email protected]
FirstName -> Paul
LastName -> White
Id -> null

Я пытаюсь сделать это с потоками java8, но могу сделать это и в «старом» стиле.

При поиске в stackoverflow я нашел аналогичный вопрос [1] и еще несколько, также связанных [2,3,4], которые дали мне некоторые идеи, но не были полностью адаптированы.

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

List result = (...)
map.forEach(h -> {
    MultiValueMap<String, String> m = new LinkedMultiValueMap();
    h.entrySet().stream().forEach(e -> {
        String[] ss = e.getValue() == null ? null : e.getValue().toString().split(",");
        if (ss != null) {
            Arrays.asList(ss).stream().forEach(s -> m.add(e.getKey(), s));
        }
    });
    if (m.size() > 0) {
        int x = m.values().stream().max((o1, o2) -> o1.size() - o2.size()).get().size();
        for (int i = 0; i < x; i++) {
            Map<String, String> n = (Map) h.clone();
            Iterator<Map.Entry<String, String>> it = n.entrySet().iterator();
            while( it.hasNext()){
                Map.Entry<String, String> e = it.next();
                List<String> ss = m.get(e.getKey());
                if(ss!=null) {
                    e.setValue(ss.get(i));
                }
            }
            result.add(n);
        }
    }
});

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

Итак, сначала это было просто, и я закончил с этим беспорядком, есть ли лучший способ сделать это?

Заранее спасибо.

[1] Потоки Java8: карта транспонирования со значениями в виде списка

[2] изменение ключей/значений - создать новый экземпляр HashMap

[3] Транспонировать хэш-карту для ключа-›значение в значение- ›ключ?

[4] обратная карта Java

15.08.2016

Ответы:


1

Как насчет этого (если я все правильно понял):

    Multimap<String, String> map = ArrayListMultimap.create();
    map.put("MiddleName", null);
    map.putAll("EmailAddress", ImmutableList.of("[email protected]", "[email protected]", "[email protected]"));

    // that's the key with the "biggest" collection within the map
    int biggest = map.asMap().entrySet().stream().collect(Collectors.reducing(0, entry -> entry.getValue().size(), Integer::max));

    Multimap<String, String> newMap = ArrayListMultimap.create();

    // "padding" the collection when required
    map.keySet().stream().forEach(key -> {
        int currentSize = map.get(key).size();
        newMap.putAll(key, map.get(key));
        if (currentSize < biggest) {
            newMap.putAll(key, Collections.nCopies(biggest - currentSize, (String) null));
        }
    });

    System.out.println(newMap); // {MiddleName=[null, null, null], EmailAddress=[[email protected], [email protected], [email protected]]}
}

Сопоставление с некоторым объектом Person отсюда довольно просто.

15.08.2016

2

Честно говоря, я бы в первую очередь попытался избежать такой ситуации и начал бы использовать реальные объекты вместо карт (даже ваш желаемый список карт действительно должен быть List<Person>), но я бы сделал это так:

Map<String, List<String>> multiMap = ...;
List<Map<String, String>> result = new ArrayList<>();

// find an entry with a non-null value, and get the size of the
// list
OptionalInt sizeOfLists =
    multiMap.values()
            .stream()
            .filter(Objects::nonNull)
            .mapToInt(List::size)
            .findAny();

// for each index, create a person and put each key and the
// corresponding value at that index in that map
sizeOfLists.ifPresent(size -> {
    for (int i = 0; i < size; i++) {
        int index = i;
        Map<String, String> person = new HashMap<>();
        result.add(person);
        multiMap.entrySet()
                .stream()
                .filter(entry -> entry.getValue() != null)
                .forEach(entry -> person.put(entry.getKey(), entry.getValue().get(index)));
    }
});

Обратите внимание, что ваш код не так уж и ужасен. Но было бы намного читабельнее, если бы вы давали вашим переменным осмысленные имена вместо h, m, e, ss.

15.08.2016
  • Привет, спасибо за ваш ответ. К сожалению, я не могу избежать этой ситуации, так как это часть более крупного потока операций. Ваш код вполне читаем, я могу понять его, просто взглянув на него. Я собираюсь попробовать, так как мой реальный сценарий немного сложнее, чем этот. А что касается моих имен переменных, то вы, конечно, правы... :) Я дам вам знать, как все пойдет. Ваше здоровье. 15.08.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 , и использованием..

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