Как эффективно обработать HashMap в порядке, описанном списком? - PullRequest
3 голосов
/ 10 февраля 2020

Это моя проблема: у меня есть список имен событий в хронологическом порядке, пример:

ArrayList<String> eventsOrder = new ArrayList<>(Arrays.asList("event1", "event2", "event3", "event4", "event5"));

У меня есть HashMap данных о событиях, где ключом является имя события, пример:

HashMap<String, String> eventsData = new HashMap<>();
    eventsData.put("event2", "data2");
    eventsData.put("event1", "data1");
    eventsData.put("event3", "data3");

У меня также есть метод, который объединяет данные из двух событий в 1:

public String merge(String previousEventsData, String nextEventsData);

Мне нужно объединить данные всех событий в один объект в хронологическом порядке . Так что в этом случае это будет что-то вроде этого:

merge(merge("data1", "data2"),"data3");

Вот как я решаю это сейчас:

Во-первых, этот HashMap может содержать или не содержать данные обо всех событиях, поэтому я отфильтруйте имена доступных:

ArrayList<String> eventsToProcess = eventsOrder.stream()
                .filter(eventName -> eventsData.containsKey(eventName))
                .collect(Collectors.toCollection(ArrayList::new));

Затем я использую этот уродливый алгоритм для объединения данных событий в хронологическом порядке:

    String finalData = "";

    int eventsCount = namesToProcess.size();

    finalData = eventsData.get(namesToProcess.get(0));
    if(eventsCount > 1) {
        for (int i = 1; i < eventsCount; i++){
            finalData = merge(finalData, eventsData.get(namesToProcess.get(i)));
        }

    }

Не очень элегантно и читабельно, верно?

Вопрос: Как мне выполнить ту же обработку с Java потоками или рекурсивной функцией?

1 Ответ

6 голосов
/ 10 февраля 2020

Что-то вроде этого должно быть эквивалентно, используя Stream.reduce:

eventsOrder.stream()          // "event1", "event2", "event3", "event4", "event5"
    .map(eventsData::get)     // "data1", "data2", "data3", null, null
    .filter(Objects::nonNull) // "data1", "data2", "data3"
    .reduce(YourClass::merge) // merge(merge("data1", "data2"), "data3")
    .get()                    // gets the result from the Optional

Метод Optional.get выдает NoSuchElementException, если нет событий с данными; в этом случае namesToProcess.get(0) вашего исходного кода выдаст IndexOutOfBoundsException. Это должно быть единственным различием в поведении, если ваша карта eventsData не имеет значений null.

...