Prozac
Prozac

Reputation: 25

Combine keys and values of a HashMap to a Set

I have a HashMap<Integer, Integer>, There can be duplicate values for the unique keys. Is there a way to convert the HashMap to a Set<Integer> which contains unique Integers of both the keys and values.

This can definitely be done in two loops by iterating over the keySet() and .values(). I'm would like to know whether this is possible in java 8 streams.

Upvotes: 2

Views: 4428

Answers (4)

Dariusz
Dariusz

Reputation: 22241

You can iterate once over entry set, which will give you all pairs. Whether you do it through streams api or not is irrelevant, because the complexity of this operation remains the same.

public class StreamMapTest {

    public static void main(String[] args) {
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        map.put(1, 20);
        map.put(2, 20);
        map.put(3, 10);
        map.put(4, 30);
        map.put(5, 20);
        map.put(6, 10);

        Set<Integer> result = map.entrySet().stream()
            .flatMap(e -> Stream.of(e.getKey(), e.getValue()))
            .collect(Collectors.toSet());

        System.out.println(result);
    }
}

Upvotes: 1

MartinS
MartinS

Reputation: 2790

You can just get all keys as a set and then add all values with addAll

Map<Integer, Integer> map = ...
Set<Integer> set = new HashSet<>(map.keySet());
set.addAll(map.values());

If you really really want to use Java 8 streams you can do the following but I don't see how this would be any better:

Map<Integer, Integer> map = ...
Set<Integer> set = new HashSet<>();
map.keySet().stream().forEach(n -> set.add(n));
map.values().stream().forEach(n -> set.add(n));

Or look at all the other solutions but in my opinion a simple addAll works best here. It should be the most efficient and definetelly the most readable way to do it.

Upvotes: 1

JB Nizet
JB Nizet

Reputation: 691635

Calling addAll() twice is simple as hell and very readable, so that should be your solution. But if you want your curiosity to be satisfied, you can use this stream based solution (less readable, probably less efficient):

Map<Integer, Integer> map = ...;
Set<Integer> result = map.entrySet()
                         .stream()
                         .flatMap(e -> Stream.of(e.getKey(), e.getValue()))
                         .collect(Collectors.toSet());

Upvotes: 4

Ferrybig
Ferrybig

Reputation: 18824

You can use the stream function to combine both the values and the keys:

Map<Integer, Integer> map = ...
Set<Integer> total = Stream.concat(
     map.keySet().stream(), 
     map.values().stream()
).collect(Collectors.toSet());

This uses the map's keySet().stream() and values().stream() to get a stream of both, then connects them using Stream.concat, then finally turns it into a set. The call to .toSet() prevents duplicate elements, because a set cannot contain duplicate elements.

This trick can also be used if the keys are double, and the values are floats, in this case java will give the greatest common divider class back, what in this case is Number.

Upvotes: 8

Related Questions