17

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?

2
  • I think looping is the best way in this context - when the size of these two arrays are same. Commented May 20, 2015 at 3:18
  • Why store in array in the first place? Commented May 20, 2015 at 3:30

6 Answers 6

38

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.

Sign up to request clarification or add additional context in comments.

3 Comments

and what about java 7 and below?
@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!
@sprinter Good answer, but he needs boxed() as Jens said below.
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)?

5 Comments

How do I do this while also sorting the hashmap in descending/ascending order?
@ColstonBod-oy 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.
yup! it does work, how can I do descending order as well?
@ColstonBod-oy .sorted(Comparator.comparing(i -> shortNames[i], Comparator.reverseOrder()))
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.")
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"}});

Comments

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

Comments

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

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.