我有这样的数据列表;
{id, datastring}
{1,"a:1|b:2|d:3"}
{2,"a:2|c:2|c:4"}
{3,"a:2|bb:2|a:3"}
{4,"a:3|e:2|ff:3"}
我需要做的是执行平均操作或查找字符串中元素小于某个值的所有id。
以下是一些例子;
平均值
{a,2}{b,2}{bb,2}{c,3}{d,3}{e,2}{ff,3}
找到c< 4
的所有id{2}
找到所有id的< 3
{1,2,3}
这可以很好地利用stream()和filter()??
答案 0 :(得分:1)
是的,您可以使用流操作来实现此目的,但我建议为此数据创建一个类,以便每行对应一个特定实例。这将使你的生活更轻松IMO。
class Data {
private int id;
private Map<String, List<Integer>> map;
....
}
那说让我们来看看如何实现这一点。首先,找到所有的实现:
public static Set<Integer> ids(List<Data> list, String value, Predicate<Integer> boundPredicate) {
return list.stream()
.filter(d -> d.getMap().containsKey(value))
.filter(d -> d.getMap().get(value).stream().anyMatch(boundPredicate))
.map(d -> d.getId())
.collect(toSet());
}
这个很容易阅读。您从列表中获得Stream<Data>
。然后应用一个过滤器,以便只获取具有地图中给定值的实例,并且有一个值满足您给出的谓词。然后,将每个实例映射到其对应的id,然后在Set中收集生成的流。
电话示例:
Set<Integer> set = ids(list, "a", value -> value < 3);
输出:
[1, 2, 3]
平均要求有点棘手。我最后得到了另一个实现,你最后得到一个Map<String, IntSummaryStatistics>
(包含平均值),还有其他信息。
Map<String, IntSummaryStatistics> stats = list.stream()
.flatMap(d -> d.getMap().entrySet().stream())
.collect(toMap(Map.Entry::getKey,
e -> e.getValue().stream().mapToInt(i -> i).summaryStatistics(),
(i1, i2) -> {i1.combine(i2); return i1;}));
首先获得Stream<Data>
,然后flatMap
每个地图的每个条目集都有Stream<Entry<String, List<Integer>>
。现在,您将此流收集到一个映射中,每个键由条目键映射,每个List<Integer>
由相应的IntSummaryStatistics
值映射。如果您有两个相同的键,则可以组合各自的IntSummaryStatistics
值。
根据您的数据集,您会得到Map<String, IntSummaryStatistics>
ff => IntSummaryStatistics{count=1, sum=3, min=3, average=3.000000, max=3}
bb => IntSummaryStatistics{count=1, sum=2, min=2, average=2.000000, max=2}
a => IntSummaryStatistics{count=5, sum=11, min=1, average=2.200000, max=3}
b => IntSummaryStatistics{count=1, sum=2, min=2, average=2.000000, max=2}
c => IntSummaryStatistics{count=2, sum=6, min=2, average=3.000000, max=4}
d => IntSummaryStatistics{count=1, sum=3, min=3, average=3.000000, max=3}
e => IntSummaryStatistics{count=1, sum=2, min=2, average=2.000000, max=2}
您可以从中轻松获取平均值。
这里有一个完整的working example,但实施当然可以改进。
答案 1 :(得分:0)
我知道你有答案,但这也是我的版本:
Map<String, Double> result = list.stream()
.map(Data::getElements)
.flatMap((Multimap<String, Integer> map) -> {
return map.entries().stream();
})
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.averagingInt((Entry<String, Integer> token) -> {
return token.getValue();
})));
System.out.println(result);
List<Integer> result2 = list.stream()
.filter((Data data) -> {
return data.getElements().get("c").stream().anyMatch(i -> i < 4);
})
.map(Data::getId)
.collect(Collectors.toList());
System.out.println(result2);