Home > Back-end >  Separate Array list based on object's field
Separate Array list based on object's field

Time:01-31

I have a class Obj like :

public class Obj{
    private String size
    private String shape
    private String name
}

In one of my other classes I have a Map<String,List<Obj>>.
For each String in my Map, I want to regroup every Obj from my List where shape and/or size are equals, based on the String of my Map.
For now I have something like :

functionName(Map<String, List<Obj>> objMap){
    objMap.foreach((type,objs) -> {
        switch(type){
            case "type_1":
                // regroup objs by shape
                // then do some treatment
            case "type_2":
                // regroup objs by size
                // then do some treatment
            case "type_3":
                // regroup objs by shape & size
                // then do some treatment
        }
    }
}

From here I'm kinda stuck on how to get a List<List<Obj>> from my List<Obj>. Any idea would help me, even if not very optimized.

Values and expected result :

For example I have a Map as :

{
  "key" :"type_1",
  "value" : [
    {
      "size" : "m1",
      "shape" : "s1",
      "name":"Obj_1"
    },
    {
      "size" : "m2",
      "shape" : "s1",
      "name":"Obj_2"
    },
    {
      "size" : "m3",
      "shape" : "s2",
      "name":"Obj_3"
    }
  ]
}

Then in my function I should be in case "type_1" so i'll group them by shape, return me something like :

[
  [
    {
      "size" : "m1",
      "shape" : "s1",
      "name":"Obj_1"
    },
    {
      "size" : "m2",
      "shape" : "s1",
      "name":"Obj_2"
    }
  ],
  [
    {
      "size" : "m3",
      "shape" : "s2",
      "name":"Obj_3"
    }
    
  ]
]

But if my key was type_3, I should have :

[
  [
    {
      "size" : "m1",
      "shape" : "s1",
      "name":"Obj_1"
    }
  ],
  [
    {
      "size" : "m2",
      "shape" : "s1",
      "name":"Obj_2"
    }
  ],
  [
    {
      "size" : "m3",
      "shape" : "s2",
      "name":"Obj_3"
    }
  ]
]

because none of them have the same shape and size

If my Map was :

{
  "key" :"type_3",
  "value" : [
    {
      "size" : "m1",
      "shape" : "s1",
      "name":"Obj_1"
    },
    {
      "size" : "m2",
      "shape" : "s1",
      "name":"Obj_2"
    },
    {
      "size" : "m1",
      "shape" : "s1",
      "name":"Obj_3"
    }
  ]
}

then I should get :

[
  [
    {
      "size" : "m1",
      "shape" : "s1",
      "name":"Obj_1"
    },
    {
      "size" : "m1",
      "shape" : "s1",
      "name":"Obj_3"
    }
  ],
  [
    {
      "size" : "m2",
      "shape" : "s1",
      "name":"Obj_2"
    }
  ]
]

CodePudding user response:

Case for shape (but you get the idea):

 List<List<Obj>> regroup(List<Obj> objs) {
    return new ArrayList<>(
       objs.stream()
         .collect(Collectors.groupingBy(Obj::getShape))
         .values()
    );
 }

CodePudding user response:

Define a List<List<Obj>> finalList. Keep a map to trace the index of the list for certain type in the finalList.

Map<String, Integer> indexMap;

Whenever you get a object of type1, try to get list like this

List<Obj> l1 = indexMap.getOrElse(new ArrayList());

Then append the object to that list and put back in index of the final list.

        List<List<Obj>> finalList = new ArrayList<>();
        Map<String, Integer> indexMap = new HashMap<>();
        
        functionName(Map<String, List<Obj>> objMap){
            objMap.foreach((type,objs) -> {
                switch(type){
                    case "type_1":
                        Integer index = indexMap.getOrDefault(type_1, -1);
                        List<Obj> list = index != -1 ? finalList.get(index) : new ArrayList<Obj>();
                        list.add(obj);
                        finalList.add(index, list); // do this for other types
                        // regroup objs by shape
                        // then do some treatment
                    case "type_2":
                        // regroup objs by size
                        // then do some treatment
                    case "type_3":
                        // regroup objs by shape & size
                        // then do some treatment
                }
            }
        }

CodePudding user response:

You should try to create nested Map<String, Map<String, List<Obj>>> to store values after grouping.

For example:

Map<String, Map<String, List<Obj>>> results = new HashMap<>();

Although, I would create another class for grouped records to make the code more readable:

class GroupedObj{
   Map<String, List<Obj>> records = new HashMap<>(); 
}

Map<String, GroupedObj> results = new HashMap<>();

CodePudding user response:

You should be able to use the groupingBy collector:

Map<String, List<Obj>> yourMap = ...;
List<List<Obj>> byShape = new ArrayList<>(yourMap.values().stream()
  .flatMap(Collection::stream)
  .collect(Collectors.groupingBy(Obj::getShape))
  .values());

As a method:

static <T> List<List<Obj>> partition(
    final Map<String, List<Obj>> map,
    final Function<? super Obj, ? extends T> key) {
  return new ArrayList<>(map.values().stream() // Stream<List<Obj>>
      .flatMap(Collection::stream) // Stream<Obj>
      .collect(Collectors.groupingBy(key)) // Map<T, List<Obj>>
      .values() // Collection<List<Obj>>
  ); // List<List<Obj>>
}

Calling the method:

final Map<String, List<Obj>> yourMap = ...;
final List<List<Obj>> shapes = partition(yourMap, Obj::getShape);

If you have extracted the list only and do not need to process a map – in that case the "map"-part is irrelevant for the question and should/could be removed – the method looks almost identical (the classic "left as an exercise to the reader", but here it goes):

static <T> List<List<Obj>> partition(
    final List<Obj> list,
    final Function<? super Obj, ? extends T> key) {
  return new ArrayList<>(list.stream() // Stream<Obj>
      .collect(Collectors.groupingBy(key)) // Map<T, List<Obj>>
      .values() // Collection<List<Obj>>
  ); // List<List<Obj>>
}

Usage:

final List<Obj> yourList = ...;
final List<List<Obj>> shapes = partition(yourList, Obj::getShape);
  • Related