First of all, this question is from my real work. I need to solve it and I do some trade off working to realize it unperfect. What's more, I abstract and simplify the basic data structure to avoid sensitive data.
My source and target Object which is Src and Tgt is as followed:
public class Src {
int id;
boolean flag;
int count;
// Constructor Getter and Setter methods......
}
public class Tgt {
int id;
int true_count;
int false_count;
// Constructor Getter and Setter methods......
}
Now I have a list of Src Object named srcList. I want to combine the list to one Object named Tgt which operation is like count how many flag in Src Object is true or false in the list.
In java8 Stream, I haved tried to use flatmap and map operator to convert List to one Object like followed code:
public class TestSrc2Tgt {
public List<Tgt> listSrc2ListTgt(List<Src> srcList){
Tgt tgt = new Tgt();
for(Src src : srcList) {
tgt.setId(src.getId());
if(src.isFlag()) {
tgt.setTrue_count(tgt.getTrue_count + src.getCount());
}
else {
tgt.setFalse_count(tgt.getFalse_count + src.getCount());
}
}
/* it is my question and I do not want to use List
What I want is convert List<Src> to Tgt which is a kind of combine srcList
*/
List<Tgt> tgtList = new ArrayList<>();
tgtList.add(tgt);
return tgtList;
}
public static void main(String[] args){
TestSrc2Tgt testSrc2Tgt = new TestSrc2Tgt();
List<Src> srcList = new ArrayList<>();
srcList.add(new Src(1, true, 15));
srcList.add(new Src(1, false, 20));
srcList.add(new Src(1, false, 110));
srcList.add(new Src(2, true, 40));
srcList.add(new Src(2, false, 250));
srcList.add(new Src(2, true, 420));
// 1. Cluster the id and generate list by id
Map<Integer, List<Src>> srcMap = srcList.stream()
.collect(Collectors.groupingBy(Src::getId, Collectors.toList()));
// 2. Count how many Src flag is true or false by listSrc2ListTgt method
// Where I hate is here
List<Tgt> tgtMaplist =
srcMap.entrySet().stream().map( e -> {return testSrc2Tgt.listSrc2ListTgt(e.getValue());})
.map(item->item.get(0)).collect(Collectors.toList());
tgtMaplist.stream().forEach(t -> {
System.out.println(t.getId());
System.out.println(t.getFalse_count());
System.out.println(t.getTrue_count());
});
}
}
The code could really work but I hate the listSrc2ListTgt() method and .map(item->item.get(0)) in getting List<Tgt> tgtMaplist. My idea is a one way converting from List<Src> to Tgt but not convert from List<Src> to List<Tgt>(only one element) and then get Tgt from List<Tgt>. It is a wasted and unperfect way of realizing.
In ideal situation
public Tgt listSrc2ListTgt(List<Src> srcList){
Tgt tgt = new Tgt();
for(Src src : srcList) {
tgt.setId(src.getId());
if(src.isFlag()) {
tgt.setTrue_count(src.getCount());
}
else {
tgt.setFalse_count(src.getCount());
}
}
return tgt;
}
And in main method:
List<Tgt> tgtMaplist = srcMap.entrySet().stream()
.map( e -> {return testSrc2Tgt.listSrc2ListTgt(e.getValue());})
.collect(Collectors.toList());
It is more comfortable. Because there is no intermediate process taken from the tgtlist by using .get(0) method, which seems less redundant. However the ideal code is unable to pass the compiler.