-1

I have two Maps map1 and map2. I want to combine both these Maps in specific order. Assume I have two maps

Map<String, String> map1 = new HashMap<>();
Map<String, String> map2 = new HashMap<>();

map1.put("id1", "3895");
map1.put("id2", "6754");
map1.put("id3", "7896");
map1.put("id4", "1122");

map2.put("month1", "Jan");
map2.put("month2", "Mar");
map2.put("month3", "Dec");
map2.put("month4", "Aug");

Now I want to combine these two maps so that the third map will have elements in below order. Expected order in Map3.

("id1", "3895")
("month1", "Jan")
("id2", "6754")
("month2", "Mar")
("id3", "7896")
("month3", "Dec")
("id4", "1122")
("month4", "Aug")

How do I achieve this? I tried with putAll and LinkedHashMap but the resulting order is not the expected one.

With LinkedHashMap -

Map<String, String> merged = Stream.concat(map1.entrySet().stream(), map2.entrySet().stream())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (x, y) -> y, LinkedHashMap::new));

and the result is

("id1", "3895")
("id2", "6754")
("id3", "7896")
("id4", "1122")
("month1", "Jan")
("month2", "Mar")
("month3", "Dec")
("month4", "Aug")

which is not my expected one.

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Nicolas
  • 554
  • 2
  • 11
  • 27
  • Does this answer your question? [Java Ordered Map](https://stackoverflow.com/questions/663374/java-ordered-map) – Ken Y-N Jul 08 '20 at 04:41
  • [This one might also](https://stackoverflow.com/q/683518/1270789) answer your question. – Ken Y-N Jul 08 '20 at 04:43
  • 2
    You don't say what type of `Map` you used for the third map, but a `HashMap` won't work because `HashMap`s have no order. You should be able to achieve what you want by using a `LinkedHashMap` (which maintains entries in insertion order) and inserting the items individually in the desired order. – Kevin Anderson Jul 08 '20 at 04:45
  • does the both maps always have same number of keys? – deadshot Jul 08 '20 at 04:45
  • @KenY-N No both info that you shared doesn't help me. I was looking for merging two maps in specific order. – Nicolas Jul 08 '20 at 04:46
  • @deadshot yes both have same number of keys – Nicolas Jul 08 '20 at 04:47
  • 1
    @Nicolas Since the two maps you currently have are `HashMap` objects, which are **unordered** maps, merging them in *specific order* makes no sense at all. – Andreas Jul 08 '20 at 04:47
  • @KevinAnderson I know how to order individual map but I was looking for merging two maps into one in above specific order. – Nicolas Jul 08 '20 at 04:48
  • Have you tried iterating them both in parallel and adding entries to a [`LinkedHashMap`](https://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html), i.e. a map that maintains **insertion order**? – Andreas Jul 08 '20 at 04:49
  • @Andreas can you share the code for that? – Nicolas Jul 08 '20 at 04:50
  • 4
    @Nicolas Can you make an attempt yourself? StackOverflow is not a write-my-code-for-me site. Which part of what I said do you find too hard to overcome by yourself, even with the help of web searches? – Andreas Jul 08 '20 at 04:51
  • @Andreas if I had the solution I wouldn't have posted the question here. I already tried with LinkedHashMap but the result I got is map2 is appended map1. i.e . ("id1", "3895") ("id2", "6754") ("id3", "7896") ("id4", "1122") ("month1", "Jan") ("month2", "Mar") ("month3", "Dec") ("month4", "Aug") – Nicolas Jul 08 '20 at 05:26
  • *" I already tried with LinkedHashMap"* --- Then **edit** the question and show what you tried, so we might help you figure out what you did wrong. Though from what you showed, you **didn't iterate** the two input maps **in parallel**, i.e. at the same time, like I said you should. You did read what I said, right? – Andreas Jul 08 '20 at 05:31

2 Answers2

1

As suggested by @Andreas, you can iterate over maps in parallel and to LinkedHashMap to maintain order,

Map<String, String> result = new LinkedHashMap<>();
Iterator<Map.Entry<String, String>> iter1 = map1.entrySet().iterator();
Iterator<Map.Entry<String, String>> iter2 = map2.entrySet().iterator();
while(iter1.hasNext() || iter2.hasNext()) {
    Map.Entry<String, String> e1 = iter1.next();
    Map.Entry<String, String> e2 = iter2.next();

    result.put(e1.getKey(), e1.getValue());
    result.put(e2.getKey(), e2.getValue());

}

If keys of both the maps are like id1, id2, month1, month2, then you can use a custom Comparator with number for sort as below,

Comparator<Map.Entry<String, String>> comparator = Comparator.comparing(c -> c.getKey().replaceAll("^\\D+", ""))  ;
Map<String, String> collect = Stream.concat(map1.entrySet().stream(), map2.entrySet().stream())
        .sorted(comparator)
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,(oldValue, newValue) -> oldValue, LinkedHashMap::new));
Vikas
  • 6,868
  • 4
  • 27
  • 41
  • Thanks a lot Code_Mode, it really helped :) – Nicolas Jul 08 '20 at 05:51
  • 2
    Your first code will fail when using two maps with different sizes. Further, it can’t change the fact that the `HashMap`s of the question’s code do not have a defined iteration order to begin with. So it doesn’t help that the resulting `LinkedHashMap` will remember that unspecified order. – Holger Jul 08 '20 at 08:41
  • OP confirmed that both the maps have the same number of keys. But I agree with your second point. – Vikas Jul 08 '20 at 08:43
-1

To merge (interleave) the content of two maps, iterate them both in parallel and add to a LinkedHashMap, so the insertion order is retained.

  1. Create mergedMap as a LinkedHashMap

  2. Get iterator1 as an iterator for the entries of map1

  3. Get iterator2 as an iterator for the entries of map2

  4. Repeat until both iterators are at-end:

    1. If not at-end, get next entry from iterator1 and add to mergedMap.

    2. If not at-end, get next entry from iterator2 and add to mergedMap.

That's it. That's all there is to it. Now you just need to write the code doing that.

Andreas
  • 154,647
  • 11
  • 152
  • 247