Home > Mobile >  Stream API how to modify key and value in a map?
Stream API how to modify key and value in a map?

Time:02-22

I have a String - Array map thatlooks like this

dishIdQuantityMap[43]=[Ljava.lang.String;@301d55ce
dishIdQuantityMap[42]=[Ljava.lang.String;@72cb31c2
dishIdQuantityMap[41]=[Ljava.lang.String;@1670799
dishIdQuantityMap[40]=[Ljava.lang.String;@a5b3d21

What I need to do is

  1. Create a new map, where key - only numbers extracted from String like this ( key -> key.replaceAll("\\D ","");
  2. Value - first value from array like this value -> value[0];
  3. Filter an array so that only this paris left where value > 0

I've spent an hour trying to solve it myself, but fail with .collect(Collectors.toMap()); method.

Could you please help me out.

UPD: The code I've done so far is just a shame, as I fail even to filter the map.

HashMap<Long, Integer> myHashMap =  request.getParameterMap().entrySet().stream()
        .filter(e -> Integer.parseInt(e.getValue()[0]) > 0)
        .collect(Collectors.toMap(MapEntry::getKey, MapEntry::getValue));

CodePudding user response:

You can do it by using stream and an auxiliary KeyValuePair class. The KeyValuePair would be as simple as:

public class KeyValuePair {

    public KeyValuePair(String key, int value) {
        this.key = key;
        this.value = value;
    }
    
    private String key;
    private int value;
    
    //getters and setters
}

Having this class you can use streams as bellow:

Map<String, Integer> resultMap = map.entrySet().stream()
            .map(entry -> new KeyValuePair(entry.getKey().replaceAll("Key", "k"), entry.getValue()[0]))
            .filter(kvp -> kvp.value > 0)
            .collect(Collectors.toMap(KeyValuePair::getKey, KeyValuePair::getValue));

In the example I'm not replacing and filtering exactly by the conditions you need but, as you said you are having problems with the collector, you probably just have to adapt the code you currently have.

CodePudding user response:

I addressed this problem in the following order:

  • filter out entries with value[0] > 0. This step is the last on your list, but with regards to performance, it's to put this operation at the beginning of the pipeline. It might decrease the number of objects that have to be created during the execution of the map() operation;
  • update the entries. I.e. replace every entry with a new one. Note, this step doesn't require creating a custom class to represent a key-value pair, AbstractMap.SimpleEntry has been with as for a while. And now instead of instantiating AbstractMap.SimpleEntry we can simply use a static method entry() of the Map interface;
  • collect entries into the map.
    public static Map<Long, Integer> processMap(Map<String, String[]> source) {
        return source.entrySet().stream()
                .filter(entry -> Integer.parseInt(entry.getValue()[0]) > 0)
                .map(entry -> updateEntry(entry))
                .collect(Collectors.toMap(Map.Entry::getKey,
                                          Map.Entry::getValue));
    }
    private static Map.Entry<Long, Integer> updateEntry(Map.Entry<String, String[]> entry) {
        return Map.entry(parseKey(entry.getKey()), parseValue(entry.getValue()));
    }

The logic for parsing keys and values was extracted into separate methods to make the code cleaner.

    private static Long parseKey(String key) {
        return Long.parseLong(key.replaceAll("\\D ",""));
    }
    private static Integer parseValue(String[] value) {
        return Integer.parseInt(value[0]);
    }
    public static void main(String[] args) {
        System.out.println(processMap(Map.of("48i;", new String[]{"1", "2", "3"},
                                            "129!;", new String[]{"9", "5", "9"})));
    }

Output

{48=1, 129=9}
  •  Tags:  
  • java
  • Related