0

I have a Map of type <String, List<Object>> where the keys of this Map are names (String) associated with an Object that contains X and Y coordinates.

Example:

Names (String)    Coordinates

Cord1             [[0.1,0.1,0.1],[0.2,0.3,0.4]]
Cord1,Cord2       [[0.1,0.1]    ,[0.4,0.5]]         
Cord1,Cord2,Cord3 [[0.1,0.1]    ,[0.6,0.7]]

What I want to achieve is to split the names when there is a comma , so I can have only single names, which will also affect the coordinates and avoid repetition.

Example of what I would like to achieve:

Cord1 [[0.1,0.1,0.1,0.1,0.1,0.1],[0.2,0.3,0.4,0.5,0.6,0.7]]
Cord2 [[0.01,0.01,0.01,0.01]    ,[0.4,0.5,0.6,0.7]]                    
Cord3 [[0.01,0.01]              ,[0.6,0.7]]

Is there a way to do this?

EDIT:

I am not very familiar with Java 8 which apparently is the most optimal way to do it, but I was experimenting with something along these lines which has not worked so far:

List<String> list = Splitter.on(',').splitToList(value);
        for (String element : list) {
           //TO-DO
        }

Cord Object:

public class Cord {
    private double X;
    private double Y;
    private String name;

    public Cord(double x, double y, String name) {
        this.X=x;
        this.Y=y;
        this.name=name;
    }
    @Override
    public String toString() {
        return "["+X+","+Y+"]";
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getX() {
        return X;
    }
    public void setX(double x) {
        X = x;
    }
    public double getY() {
        return Y;
    }
    public void setY(double y) {
        Y = y;
    }

}
John Stef
  • 585
  • 1
  • 4
  • 16

2 Answers2

1

There is stream way with flatMapping from java-9 :

import static java.util.stream.Collectors.*;

Map<String, List<Object>> collect = map.entrySet().stream()
        .flatMap(entry -> Arrays.stream(entry.getKey().split(","))
                .map(s -> new AbstractMap.SimpleEntry<>(s, entry.getValue())))
        .collect(groupingBy(Map.Entry::getKey, 
                flatMapping(entry -> entry.getValue().stream(), toList())));

If you can't use java-9 it is still can be done by stream API but it will be much more wordy. Probably in this case you should consider solution with for loop.

Map<String, List<Object>> collect1 = map.entrySet().stream()
        .flatMap(entry -> Arrays.stream(entry.getKey().split(","))
                .map(s -> new AbstractMap.SimpleEntry<>(s, entry.getValue())))
        .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())))
        .entrySet().stream()
        .flatMap(entry -> entry.getValue().stream()
                .flatMap(Collection::stream)
                .map(o -> new AbstractMap.SimpleEntry<>(entry.getKey(), o)))
        .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())));
Ruslan
  • 6,090
  • 1
  • 21
  • 36
  • I get the following error when I try to do this: Cannot infer type argument(s) for flatMap(Function super T,? extends Stream extends R>>) – John Stef Feb 18 '19 at 14:42
  • @JohnStef is it your case ? https://stackoverflow.com/questions/42285370/cannot-infer-type-arguments-for-r-mapfunction-super-t-extends-r-in-so – Ruslan Feb 18 '19 at 14:45
  • I managed to fix this, the only problem now is that it does not recognise the method toList() (is undefined for the type main). – John Stef Feb 18 '19 at 14:59
  • @JohnStef make sure you have `import static java.util.stream.Collectors.toList;` or all methods from Collectors `import static java.util.stream.Collectors.*;` – Ruslan Feb 18 '19 at 14:59
  • This fixed the `toList` method but started another error `The method flatMapping(( entry) -> {}, toList()) is undefined for the type Main`. – John Stef Feb 18 '19 at 15:09
  • @JohnStef methods `groupingBy`, `flatMapping`, `toList` are all from `Collectors` class. It means you have to either use static import for each of them, or use static import like a mentioned in the answer `import static java.util.stream.Collectors.*;`. Static imports are nedeed just for concise.. you can use these methods like `Collectors.flatMapping` etc.. – Ruslan Feb 18 '19 at 15:14
  • Apparently I cant use `import static java.util.stream.Collectors.flatMapping;` as it "complains" while it accepts `import static java.util.stream.Collectors.*` . The same when I try to add `Collectors.flatMapping` – John Stef Feb 18 '19 at 15:20
  • @JohnStef Note that `flatMapping` method is from java-9 – Ruslan Feb 18 '19 at 15:35
  • It seems Java 9 was not the issue. I get the same error `Cannot infer type argument(s) for flatMap(Function super T,? extends Stream extends R>>)` when I use the new code you mentioned. I assume there must be an error in the transformation of the map. – John Stef Feb 18 '19 at 16:06
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/188617/discussion-between-ruslan-and-john-stef). – Ruslan Feb 18 '19 at 16:13
0

This the solution for what i understood from your question:

Map<String, List<Object>> doTheThing(Map<String, List<Object>> input){
  Map<String, List<Object>> retr = new Map<String, List<Object>>();
  for(String s1:input.keySet()){//for each Name on the original map
    String[] separatedByCommas = s1.split(",");//split the names by ","
    for(String s2:separatedByCommas){//for each separated by "," name
      if(!retr.containsKey(s2)){
        //if the separated by "," name is not on the retr map just put to the separated by "," name the contents of name
        retr.put(s2,input.get(s1));
      }else{
        //if the separated by "," name is on the retr map add to the separated by "," name the contents of name
        retr.put(s2,retr.get(s2).addAll(input.get(s1));//add to whats already in s2
      }
    }
    return retr;
  }