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);