How to effectively process HashMap in order described by list?

EasternDude :

This is my problem: I have a list of event names in chronological order, example:

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

I have HashMap of data about events, where key is events name, example:

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

I also have a method that merges Data from 2 events into 1:

public String merge(String previousEventsData, String nextEventsData);

I need to merge all of events' data into one object in chronological order. So in this case it would be something like this:

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

This how I solve it now:

Firstly, this HashMap may or may not contain data about all of the events so i filter names of the ones that are available:

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

Then I use this ugly algorithm to merge events' data in chronological order:

    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)));
        }

    }

Not very elegant and readable, right?

Question: How would I do same processing with Java streams or a recursive function?

kaya3 :

Something like this should be equivalent, using 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

The Optional.get method throws NoSuchElementException if there are no events with data; your original code's namesToProcess.get(0) will throw IndexOutOfBoundsException in that case. That should be the only difference in behaviour, assuming your eventsData map doesn't have any null values.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=11975&siteId=1