How to map two arrays to one HashMap in Java?
Asked Answered
G

6

16

I have two String arrays. One having short name.

// days short name
String[] shortNames = {"SUN", "MON", "...", "SAT"};

The other having long name.

// days long name
String[] longNames = {"SUNDAY", "MONDAY", "....", "SATURDAY"};

Both having same number of elements. How can I map short name as KEY and long name as VALUE in HashMap?

HashMap<String, String> days = new HashMap<>();

I know, I can make by looping. Is there a better way?

Gehring answered 20/5, 2015 at 3:16 Comment(2)
I think looping is the best way in this context - when the size of these two arrays are same.Bivalve
Why store in array in the first place?Halonna
I
37

There are lots of ways you can do this. One that is fairly easy to understand and apply is using Java 8 streams and collectors to map from a stream of indices to key value pairs:

Map<String, String> days = IntStream.range(0, shortNames.length).boxed()
    .collect(Collectors.toMap(i -> shortNames[i], i -> longNames[i]));

There are some third party Java libraries that include a 'zip' function to take two streams and produce a map from one to the other. But really they are just neater ways of achieving the same thing as the code above.

Intercom answered 20/5, 2015 at 3:23 Comment(3)
and what about java 7 and below?Rummel
@10sw33 Below Java 8 (other than upgrading!) you still have a few options. Use a third party library or use Arrays.toList(shortNames).forEach to go through all the items in one array and add the map entries. I know this is really just iteration by another name but then so also are streams!Intercom
@Intercom Good answer, but he needs boxed() as Jens said below.Aliform
R
3

The accepted answer did not work for me, as the IntStream does not provide a one-argument collect method.

To nevertheless benefit from the toMap collector you have to box the int primitives into Integer objects first. If you like to preserve the element order, use the extended version of toMap together with LinkedHashMap::new like shown below:

package learning.java8;

import static java.util.stream.Collectors.*;
import static org.junit.Assert.*;

import java.time.DayOfWeek;
import java.time.format.TextStyle;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.stream.IntStream;

import org.junit.Test;

public class IntStreamLT {

    @Test
    public void q30339679() {

        final String[] shortNames = getDayOfWeekNamesInEnglish(TextStyle.SHORT);
        final String[] longNames = getDayOfWeekNamesInEnglish(TextStyle.FULL);

        final Map<String, String> days = IntStream.range(0, shortNames.length).boxed()
                .collect(toMap(i -> shortNames[i], i -> longNames[i]));

        System.out.println(days);

        final Map<String, String> sorted = IntStream.range(0, shortNames.length).boxed()
                .collect(toMap(
                        i -> shortNames[i], i -> longNames[i],
                        (i, j) -> i, LinkedHashMap::new));

        System.out.println(sorted);

        assertEquals("{Mon=Monday, Tue=Tuesday, Wed=Wednesday, Thu=Thursday, "
                + "Fri=Friday, Sat=Saturday, Sun=Sunday}", sorted.toString());
    }

    private static String[] getDayOfWeekNamesInEnglish(final TextStyle style) {

        return Arrays.stream(DayOfWeek.values())
                .map(day -> day.getDisplayName(style, Locale.ENGLISH))
                .toArray(String[]::new);
    }
}

see also: Why don't primitive Stream have collect(Collector)?

Runkel answered 25/3, 2017 at 10:56 Comment(5)
How do I do this while also sorting the hashmap in descending/ascending order?Sulphanilamide
@Sulphanilamide You could add e.g. .sorted(Comparator.comparing(i -> shortNames[i])) before .collect(...). If this does not help, it might be better to ask a new question.Runkel
yup! it does work, how can I do descending order as well?Sulphanilamide
@Sulphanilamide .sorted(Comparator.comparing(i -> shortNames[i], Comparator.reverseOrder()))Runkel
The accepted answer has since been fixed to call .boxed() on the IntStream before calling .collect, so it should work now. ("The accepted answer did not work for me, as the IntStream does not provide a one-argument collect method.")Sough
C
3

You can use org.apache.commons.lang3.ArrayUtils.

Here is an example:

Map colorMap = ArrayUtils.toMap(new String[][] {
    {"RED", "#FF0000"},
    {"GREEN", "#00FF00"},
    {"BLUE", "#0000FF"}});
Censorious answered 12/9, 2017 at 22:47 Comment(0)
S
0

The Google Guava library has the Streams.zip method, which will zip two streams into a single stream. The zipped stream can then be collected into a Map.

Map<String, String> days =
        Streams.zip(Arrays.stream(shortNames), Arrays.stream(longNames), Map::entry)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Sough answered 18/6, 2024 at 21:15 Comment(0)
S
0

The StreamEx library has the zipWith method, which will zip two streams into a StreamEx EntryStream. They can then be converted into a Map using EntryStream.toMap:

Map<String, String> days =
        StreamEx.of(shortNames).zipWith(StreamEx.of(longNames)).toMap();
Sough answered 18/6, 2024 at 21:17 Comment(0)
S
0

This doesn't address the general question of mapping two arbitrary arrays, but for the specific question of mapping day of week abbreviations to their long names, the java.time.DayOfWeek enum values can be streamed over and collected into a Map:

Map<String, String> days = Arrays.stream(DayOfWeek.values())
        .collect(Collectors.toMap(
                d -> d.getDisplayName(TextStyle.SHORT, Locale.ENGLISH).toUpperCase(),
                d -> d.getDisplayName(TextStyle.FULL, Locale.ENGLISH).toUpperCase()));
Sough answered 18/6, 2024 at 21:22 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.