list和jdk8上stream、filter和average的使用
Use of stream, filter and average on list and jdk8
我有这样的数据列表;
{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"}
我这里需要做的是像average这样的操作,或者找出字符串中某个元素小于某个值的所有id。
这里有一些例子;
平均值
{a,2}{b,2}{bb,2}{c,3}{d,3}{e,2}{ff,3}
查找所有 c<4
的 ID
{2}
查找所有 a<3
的 ID
{1,2,3}
这对 stream() 和 filter() 有用吗??
是的,您可以使用流操作来实现这一点,但我建议为该数据创建一个 class,以便每一行对应一个特定实例。在我看来,这将使您的生活更轻松。
class Data {
private int id;
private Map<String, List<Integer>> map;
....
}
话虽如此,让我们来看看如何实现它。首先,find all的实现:
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,但实现当然可以改进。
我知道你有答案,但这是我的版本:
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);
我有这样的数据列表;
{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"}
我这里需要做的是像average这样的操作,或者找出字符串中某个元素小于某个值的所有id。
这里有一些例子;
平均值
{a,2}{b,2}{bb,2}{c,3}{d,3}{e,2}{ff,3}
查找所有 c<4
的 ID{2}
查找所有 a<3
的 ID{1,2,3}
这对 stream() 和 filter() 有用吗??
是的,您可以使用流操作来实现这一点,但我建议为该数据创建一个 class,以便每一行对应一个特定实例。在我看来,这将使您的生活更轻松。
class Data {
private int id;
private Map<String, List<Integer>> map;
....
}
话虽如此,让我们来看看如何实现它。首先,find all的实现:
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,但实现当然可以改进。
我知道你有答案,但这是我的版本:
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);