0

I have a HashMap<Integer, List<String>> as input, e.g :

3  :  a, b, c
6  :  b, c
9  :  a, c
12 :  b ,c

I want to convert it to HashMap<String, HashSet<Integer>> for e.g.

a : 3, 9
b : 3, 6, 12
c : 3, 6, 9, 12

How can it be done ?

CodeMonkey
  • 22,825
  • 4
  • 35
  • 75
saurabh agarwal
  • 2,124
  • 4
  • 24
  • 46
  • Similar tasks have been covered on Stack Overflow before, with good answers, but they are hard to search for (I didn’t find an example readily). I still encourage you to try your search skills and luck. – Ole V.V. May 30 '17 at 13:41
  • 1
    Possible duplicate of [Java8 streams : Transpose map with values as list](https://stackoverflow.com/questions/38471056/java8-streams-transpose-map-with-values-as-list) – Ole V.V. May 30 '17 at 13:43
  • @OleV.V. Thanks for the link. This answer did help me reaching the final solution but still required some tweak. Map Response value is a HashSet instead of List. I think it can help a beginner like me. Please Let me know if you disagree. – saurabh agarwal May 30 '17 at 20:22
  • I noticed that you answered your own question. I was happy about that and hurried to upvote your answer. I believe it deserves to be here. Very glad that my link helped. – Ole V.V. May 30 '17 at 20:25

4 Answers4

2

This should help

Map<Integer, List<String>>  initMap = new HashMap<>();

initMap.put(3, new ArrayList<String>(Arrays.asList("a", "b", "c")));
initMap.put(6, new ArrayList<String>(Arrays.asList("b", "c")));
initMap.put(9, new ArrayList<String>(Arrays.asList("a", "c")));
initMap.put(12, new ArrayList<String>(Arrays.asList("b", "c")));

Map<String, Set<Integer>> finalMap = new HashMap<>();

initMap.forEach((key, values) -> {
  values.forEach(val -> {
    Object o = finalMap.containsKey(val) ? 
             finalMap.get(val).add(key) : 
             finalMap.put(val, new HashSet<Integer>(Arrays.asList(key)));
  });
});
Aliaksei Stadnik
  • 1,692
  • 3
  • 15
  • 32
1

Here's an example, along with tests:

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

import org.junit.Assert;
import org.junit.Test;

public class SoTests {
    @Test
    public void so01() {
        HashMap<Integer, List<String>> input = new HashMap<>(4);
        input.put(3, Arrays.asList("a", "b", "c"));
        input.put(6, Arrays.asList("b", "c"));
        input.put(9, Arrays.asList("a", "c"));
        input.put(12, Arrays.asList("b", "c"));

        HashMap<String, HashSet<Integer>> output = process(input);

        HashMap<String, HashSet<Integer>> expectedOutput = new HashMap<>(3);
        expectedOutput.put("a", new HashSet<>(Arrays.asList(3, 9)));
        expectedOutput.put("b", new HashSet<>(Arrays.asList(3, 6, 12)));
        expectedOutput.put("c", new HashSet<>(Arrays.asList(3, 6, 9, 12)));
        Assert.assertEquals(expectedOutput, output);
    }

    private HashMap<String, HashSet<Integer>> process(HashMap<Integer, List<String>> input) {
        return input.entrySet().stream() //
            .flatMap(entry -> entry.getValue().stream().map(s -> new IntegerAndString(entry.getKey(), s))) //
            .collect(Collectors.groupingBy(IntegerAndString::getString, HashMap::new, //
                Collectors.mapping(IntegerAndString::getInteger, Collectors.toCollection(HashSet::new))));
    }

    private static class IntegerAndString {
        private final Integer integer;
        private final String string;

        IntegerAndString(Integer integer, String string) {
            this.integer = integer;
            this.string = string;
        }

        Integer getInteger() {
            return integer;
        }

        String getString() {
            return string;
        }
    }
}

The actual logic is in the process method. The ugly IntegerAndString class is due to a lack of tuple types in Java. You can use some library like javatuples instead.

korolar
  • 1,340
  • 1
  • 11
  • 20
1

Just looking at Duplicate link.

This is the final solution I have

 private HashMap<String, HashSet<Integer>> process(HashMap<Integer, List<String>> input) {
     return input.entrySet().stream()
             .flatMap(entry -> entry.getValue().stream().map(s -> new SimpleEntry<>(entry.getKey(), s)))
             .collect(Collectors.groupingBy(SimpleEntry::getValue, HashMap::new,
                 Collectors.mapping(SimpleEntry::getKey, Collectors.toCollection(HashSet::new))));
     }
saurabh agarwal
  • 2,124
  • 4
  • 24
  • 46
  • This is a fine tweak of the answer from the linked question to fit your particular requirements (the requirement to have sets as values in the result map in particular). – Ole V.V. May 30 '17 at 20:28
0
Map<Integer, List<String>> intHM = new HashMap<Integer, List<String>>();

    intHM.put(3, new ArrayList<String>(Arrays.asList("a","b","c")));

    intHM.put(6, new ArrayList<String>(Arrays.asList("b","c")));

    intHM.put(9, new ArrayList<String>(Arrays.asList("a","c")));

    intHM.put(12, new ArrayList<String>(Arrays.asList("b","c")));

    Map<String,List<Integer>> StringHM = new HashMap<String, List<Integer>>();

    Iterator<Entry<Integer,List<String>>> iterator = intHM.entrySet().iterator();

    while (iterator.hasNext()) {

        Map.Entry<Integer,List<String>> entry = (Map.Entry<Integer,List<String>>) iterator.next();

        for(String str: entry.getValue())
        {

            if (StringHM.containsKey(str))
                StringHM.get(str).add(entry.getKey());
            else
                StringHM.put(str, new ArrayList<Integer>(Arrays.asList(entry.getKey())));

        }
    }

    Iterator<Entry<String,List<Integer>>> StringIterator = StringHM.entrySet().iterator();

    while (StringIterator.hasNext()) {

        Map.Entry<String,List<Integer>> entry = (Map.Entry<String,List<Integer>>) StringIterator.next();

        System.out.print(entry.getKey()+" ");

        for(Integer i: entry.getValue())

            System.out.print(i+" ");

        System.out.println();
    }
Sneha
  • 39
  • 6