4

I have the following TreeMap:

TreeMap<Long,String> gasType = new TreeMap<>(); // Long, "Integer-Double"
gasType.put(1L, "7-1.50");
gasType.put(2L, "7-1.50");
gasType.put(3L, "7-3.00");
gasType.put(4L, "8-5.00");
gasType.put(5L, "8-7.00");
Map<Integer,TreeSet<Long>> capacities = new TreeMap<>);

The key is of the form 1L (a Long), and value of the form "7-1.50" (a String concatenation of an int and a double separated by a -).

I need to create a new TreeMap where the keys are obtained by taking the int part of the values of the original Map (for example, for the value "7-1.50", the new key will be 7). The value of the new Map would be a TreeSet containing all the keys of the original Map matching the new key.

So, for the input above, the value for the 7 key will be the Set {1L,2L,3L}.

I can do this without Streams, but I would like to do it with Streams. Any help is appreciated. Thank you.

3 Answers 3

5

Here's one way to do it:

Map<Integer,TreeSet<Long>> capacities = 
  gasType.entrySet()
         .stream ()
         .collect(Collectors.groupingBy (e -> Integer.parseInt(e.getValue().substring(0,e.getValue ().indexOf("-"))),
                                         TreeMap::new,
                                         Collectors.mapping (Map.Entry::getKey,
                                                             Collectors.toCollection(TreeSet::new))));

I modified the original code to support integers of multiple digits, since it appears you want that.

This produces the Map:

{7=[1, 2, 3], 8=[4, 5]}

If you don't care about the ordering of the resulting Map and Sets, you can let the JDK decide on the implementations, which would somewhat simplify the code:

Map<Integer,Set<Long>> capacities = 
  gasType.entrySet()
         .stream ()
         .collect(Collectors.groupingBy (e -> Integer.parseInt(e.getValue().substring(0,e.getValue ().indexOf("-"))),
                                         Collectors.mapping (Map.Entry::getKey,
                                                             Collectors.toSet())));
Sign up to request clarification or add additional context in comments.

3 Comments

@Aominè see comment near the end that eliminates that assumption.
yup just about got to it :)
Yeah, Integers aren't always single digit and you have provided both possibilities.This is an elegant solution! Grateful to you! Thanks.
4

You may try this out,

final Map<Integer, Set<Long>> map = gasType.entrySet().stream()
        .collect(Collectors.groupingBy(entry -> Integer.parseInt(entry.getValue().substring(0, 1)),
                Collectors.mapping(Map.Entry::getKey, Collectors.toSet())));

UPDATE

If you want to split the value based on "-" since there may be more that one digit, you can change it like so:

final Map<Integer, Set<Long>> map = gasType.entrySet().stream()
        .collect(Collectors.groupingBy(entry -> Integer.parseInt(entry.getValue().split("-")[0]),
                Collectors.mapping(Map.Entry::getKey, Collectors.toSet())));

3 Comments

Is there any way to split the value based on "-" so that other than single digit also can be utilized?
I have changed the answer according to your new requirement.
Thanks @Ravindra Sir.
2

Other solution would be like this

list = gasType.entrySet()
            .stream()
            .map(m -> new AbstractMap.SimpleImmutableEntry<Integer, Long>(Integer.valueOf(m.getValue().split("-")[0]), m.getKey()))
             .collect(Collectors.toList());

and second step:

list.stream()
    .collect(Collectors.groupingBy(Map.Entry::getKey,
    Collectors.mapping(Map.Entry::getValue,Collectors.toCollection(TreeSet::new))));

or in one step:

gasType.entrySet()
            .stream()
            .map(m -> new AbstractMap.SimpleImmutableEntry<>(Integer.valueOf(m.getValue().split("-")[0]), m.getKey()))
            .collect(Collectors.groupingBy(Map.Entry::getKey,
                    Collectors.mapping(Map.Entry::getValue, Collectors.toCollection(TreeSet::new))))

3 Comments

I will try this also, Thanks! much appreciated Sir.
Why do you need to map to SimpleEntry? That just adds further overhead which can be avoided and also collecting to a list only to create a stream from it in the middle of a stream pipeline is suboptimal. I’d do all the key extraction and value extraction in the groupingBy.
You are right, but i thought it shouldn't be same with other answer.gasType.entrySet() .stream() .collect(Collectors.groupingBy(m->Integer.valueOf(m.getValue().split("-")[0]), Collectors.mapping(Map.Entry::getKey,Collectors.toCollection(TreeSet::new))));

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.