按多个分组聚合列表中的值并计算 java 中的分布百分比 8
Aggregating values in a list by multiple group by and calculating percentage of distribution in java 8
我有这样的用例,我需要按多个分组依据聚合列表中的值,然后计算每个值的分布百分比并创建一个新列表。
项目列表示例:
week1 source1 destination1 100
week1 source1 destination2 200
week1 source2 destination1 200
week1 source2 destination2 100
week2 source1 destination1 200
week2 source1 destination2 200
据此我想按周和来源分组并计算总量,然后根据数量分配百分比。
例如,来源 1 的第 1 周的总数量为 300,将运往目的地 1(100) 和目的地 2(200)。现在,第 1 周从源 1 到目标 1 的分配百分比为 33.33%,对于第 1 周从源 1 到目标 2 的分配百分比为 66.66%
例如输出将是:
week1 source1 destination1 33.33%
week1 source1 destination2 66.66%
week1 source2 destination1 66.66%
week1 source2 destination2 33.33%
week2 source1 destination1 50%
week2 source1 destination2 50%
如何使用 Java 8 个流来实现此结果。
假设我将这些对象的列表作为“记录”对象的列表:
public class Record {
private String sourceNode;
private String destinationNode;
private String weekIndex;
private String quantity;
}
Map<String, Map<String, List<Record>>> RecordsGroupByWeekAndSource = records.stream()
.collect(Collectors.groupingBy(Record::getWeekIndex, Collectors.groupingBy(Record::getSourceNode)));
这会给我按周和来源分组的项目。但是我将不得不再次迭代此地图以计算驻留在地图对象地图内的每个列表中的总数。但是有没有一种方法可以在 groupingBy 集合 itslef 中进行百分比计算?
你可以通过两次stream实现:
- 在第一个集合中,你可以做 group by 和做 sum
- 再次流式传输您的记录并使用第一步的总和结果来计算百分比
示例代码:
import java.util.*;
import java.util.stream.*;
class Record {
public String week;
public String source;
public String destination;
public Integer qty;
Record(String week, String source, String destination, Integer qty) {
this.week = week;
this.source = source;
this.destination = destination;
this.qty = qty;
}
}
public class Main {
public static void main(String[] args) {
List<Record> records = new ArrayList<>();
records.add(new Record("w1", "hyd", "kur", 10));
records.add(new Record("w1", "hyd", "gwd", 20));
records.add(new Record("w2", "hyd", "kur", 40));
records.add(new Record("w2", "hyd", "gwd", 10));
Map<String, Map<String, Integer>> sums = records
.stream()
.collect(Collectors.groupingBy(rec -> rec.week,
Collectors.groupingBy(rec -> rec.source,
Collectors.summingInt(rec->rec.qty))));
records = records
.stream()
.map(rec -> {
rec.qty = rec.qty*100 / sums.get(rec.week).get(rec.source);
return rec;
}).collect(Collectors.toList());
records.forEach((rec)->System.out.println(rec.week+"\t"+rec.source+"\t"+rec.destination+"\t"+rec.qty));
}
}
您可以创建一个地图,键为:week+source
,值为总数量。
CollectingAndThen
可以利用地图并创建结果列表:
// Value Objects:
@Data
@AllArgsConstructor
class Records {
String week, source, destination;
int quantity;
}
@Data
@AllArgsConstructor
class Distribution {
String week, source, destination;
float pctDist;
public Distribution(Records r) {
this.week = r.getWeek();
this.source = r.getSource();
this.destination = r.getDestination();
}
}
import static java.util.stream.Collectors.*;
public class SO {
public static void main(String[] args) {
List<Record> recordList = List.of(
new Record("week1", "source1", "destination1", 100),
new Record("week1", "source1", "destination2", 200),
new Record("week1", "source2", "destination1", 200),
new Record("week1", "source2", "destination2", 100),
new Record("week2", "source1", "destination1", 200),
new Record("week2", "source1", "destination2", 200));
Function<Map<String, Integer>, List<Distribution>> distExtractor =
totalQuantityMap -> recordList.stream().map(r -> getDistribution(r,totalQuantityMap)).collect(toList());
List<Distribution> result =
recordList.stream().collect(collectingAndThen(groupingBy(r -> r.getWeek() + r.getSource(),
summingInt(Record::getQuantity)),
distExtractor));
// print the result
result.forEach((rec) -> System.out.println(rec.week + "\t" + rec.source + "\t" + rec.destination + "\t" + rec.pctDist));
}
private static Distribution getDistribution(Record r, Map<String, Integer> weekAndSourceToTotalQuantityMap) {
int total = weekAndSourceToTotalQuantityMap.get(r.getWeek() + r.getSource());
float pctDist = (r.getQuantity() * 100) / total;
var dist = new Distribution(r);
dist.setPctDist(pctDist);
return dist;
}
}
输出:
// Precision can be worked upon in getDistribution method
week1 source1 destination1 33.0
week1 source1 destination2 66.0
week1 source2 destination1 66.0
week1 source2 destination2 33.0
week2 source1 destination1 50.0
week2 source1 destination2 50.0
我有这样的用例,我需要按多个分组依据聚合列表中的值,然后计算每个值的分布百分比并创建一个新列表。
项目列表示例:
week1 source1 destination1 100
week1 source1 destination2 200
week1 source2 destination1 200
week1 source2 destination2 100
week2 source1 destination1 200
week2 source1 destination2 200
据此我想按周和来源分组并计算总量,然后根据数量分配百分比。
例如,来源 1 的第 1 周的总数量为 300,将运往目的地 1(100) 和目的地 2(200)。现在,第 1 周从源 1 到目标 1 的分配百分比为 33.33%,对于第 1 周从源 1 到目标 2 的分配百分比为 66.66%
例如输出将是:
week1 source1 destination1 33.33%
week1 source1 destination2 66.66%
week1 source2 destination1 66.66%
week1 source2 destination2 33.33%
week2 source1 destination1 50%
week2 source1 destination2 50%
如何使用 Java 8 个流来实现此结果。
假设我将这些对象的列表作为“记录”对象的列表:
public class Record {
private String sourceNode;
private String destinationNode;
private String weekIndex;
private String quantity;
}
Map<String, Map<String, List<Record>>> RecordsGroupByWeekAndSource = records.stream()
.collect(Collectors.groupingBy(Record::getWeekIndex, Collectors.groupingBy(Record::getSourceNode)));
这会给我按周和来源分组的项目。但是我将不得不再次迭代此地图以计算驻留在地图对象地图内的每个列表中的总数。但是有没有一种方法可以在 groupingBy 集合 itslef 中进行百分比计算?
你可以通过两次stream实现:
- 在第一个集合中,你可以做 group by 和做 sum
- 再次流式传输您的记录并使用第一步的总和结果来计算百分比
示例代码:
import java.util.*;
import java.util.stream.*;
class Record {
public String week;
public String source;
public String destination;
public Integer qty;
Record(String week, String source, String destination, Integer qty) {
this.week = week;
this.source = source;
this.destination = destination;
this.qty = qty;
}
}
public class Main {
public static void main(String[] args) {
List<Record> records = new ArrayList<>();
records.add(new Record("w1", "hyd", "kur", 10));
records.add(new Record("w1", "hyd", "gwd", 20));
records.add(new Record("w2", "hyd", "kur", 40));
records.add(new Record("w2", "hyd", "gwd", 10));
Map<String, Map<String, Integer>> sums = records
.stream()
.collect(Collectors.groupingBy(rec -> rec.week,
Collectors.groupingBy(rec -> rec.source,
Collectors.summingInt(rec->rec.qty))));
records = records
.stream()
.map(rec -> {
rec.qty = rec.qty*100 / sums.get(rec.week).get(rec.source);
return rec;
}).collect(Collectors.toList());
records.forEach((rec)->System.out.println(rec.week+"\t"+rec.source+"\t"+rec.destination+"\t"+rec.qty));
}
}
您可以创建一个地图,键为:week+source
,值为总数量。
CollectingAndThen
可以利用地图并创建结果列表:
// Value Objects:
@Data
@AllArgsConstructor
class Records {
String week, source, destination;
int quantity;
}
@Data
@AllArgsConstructor
class Distribution {
String week, source, destination;
float pctDist;
public Distribution(Records r) {
this.week = r.getWeek();
this.source = r.getSource();
this.destination = r.getDestination();
}
}
import static java.util.stream.Collectors.*;
public class SO {
public static void main(String[] args) {
List<Record> recordList = List.of(
new Record("week1", "source1", "destination1", 100),
new Record("week1", "source1", "destination2", 200),
new Record("week1", "source2", "destination1", 200),
new Record("week1", "source2", "destination2", 100),
new Record("week2", "source1", "destination1", 200),
new Record("week2", "source1", "destination2", 200));
Function<Map<String, Integer>, List<Distribution>> distExtractor =
totalQuantityMap -> recordList.stream().map(r -> getDistribution(r,totalQuantityMap)).collect(toList());
List<Distribution> result =
recordList.stream().collect(collectingAndThen(groupingBy(r -> r.getWeek() + r.getSource(),
summingInt(Record::getQuantity)),
distExtractor));
// print the result
result.forEach((rec) -> System.out.println(rec.week + "\t" + rec.source + "\t" + rec.destination + "\t" + rec.pctDist));
}
private static Distribution getDistribution(Record r, Map<String, Integer> weekAndSourceToTotalQuantityMap) {
int total = weekAndSourceToTotalQuantityMap.get(r.getWeek() + r.getSource());
float pctDist = (r.getQuantity() * 100) / total;
var dist = new Distribution(r);
dist.setPctDist(pctDist);
return dist;
}
}
输出:
// Precision can be worked upon in getDistribution method
week1 source1 destination1 33.0
week1 source1 destination2 66.0
week1 source2 destination1 66.0
week1 source2 destination2 33.0
week2 source1 destination1 50.0
week2 source1 destination2 50.0