groupingBy 和 filter 一步到位
groupingBy and filter in one step
我有一个 Stream<String>
,我想要一个 Map<Integer, String>
。让我们调用我的分类器函数 getKey(String)
- 它可能很昂贵。有时它 returns 为零,这意味着字符串应该被丢弃并且不包含在结果映射中。
所以,我可以使用这段代码:
Stream<String> stringStream;
Map<Integer, String> result =
stringStream.collect(Collectors.groupingBy(this::getKey, Collectors.joining());
result.remove(0);
这首先将不需要的字符串添加到以零为键的映射中,然后将其删除。可能有很多。有没有一种优雅的方法可以避免首先将它们添加到地图中?
我不想在分组之前添加过滤步骤,因为那将意味着执行两次 decision/classification 代码。
你说调用 getKey
很昂贵,但你仍然可以在过滤之前映射流 up-front 的元素。在这种情况下,对 getKey
的调用只会执行一次。
Map<Integer, String> result =
stringStream.map(s -> new SimpleEntry<>(this.getKey(s), s))
.filter(e -> e.getKey() != 0)
.collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, joining())));
注意标准API中没有元组类。您可以自己制作一个或使用 AbstractMap.SimpleEntry
作为替代品。
或者,如果您认为第一个版本创建了很多条目,您可以使用 collect 方法,您自己提供供应商、累加器和组合器。
Map<Integer, String> result = stringStream
.collect(HashMap::new,
(m, e) -> {
Integer key = this.getKey(e);
if(key != 0) {
m.merge(key, e, String::concat);
}
},
Map::putAll);
您可以像这样使用成对流:
stringStream.map(x -> new Pair(getKey(x), x))
.filter(pair -> pair.left != 0) // or whatever predicate
.collect(Collectors.groupingBy(pair -> pair.left,
Collectors.mapping(pair -> pair.right, Collectors.joining())));
此代码假设简单 Pair
class 具有两个字段 left
和 right
.
像我的 StreamEx 这样的一些 third-party 库提供了额外的方法来删除样板文件:
StreamEx.of(stringStream)
.mapToEntry(this::getKey, x -> x)
.filterKeys(key -> key != 0) // or whatever
.grouping(Collectors.joining());
我有一个 Stream<String>
,我想要一个 Map<Integer, String>
。让我们调用我的分类器函数 getKey(String)
- 它可能很昂贵。有时它 returns 为零,这意味着字符串应该被丢弃并且不包含在结果映射中。
所以,我可以使用这段代码:
Stream<String> stringStream;
Map<Integer, String> result =
stringStream.collect(Collectors.groupingBy(this::getKey, Collectors.joining());
result.remove(0);
这首先将不需要的字符串添加到以零为键的映射中,然后将其删除。可能有很多。有没有一种优雅的方法可以避免首先将它们添加到地图中?
我不想在分组之前添加过滤步骤,因为那将意味着执行两次 decision/classification 代码。
你说调用 getKey
很昂贵,但你仍然可以在过滤之前映射流 up-front 的元素。在这种情况下,对 getKey
的调用只会执行一次。
Map<Integer, String> result =
stringStream.map(s -> new SimpleEntry<>(this.getKey(s), s))
.filter(e -> e.getKey() != 0)
.collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, joining())));
注意标准API中没有元组类。您可以自己制作一个或使用 AbstractMap.SimpleEntry
作为替代品。
或者,如果您认为第一个版本创建了很多条目,您可以使用 collect 方法,您自己提供供应商、累加器和组合器。
Map<Integer, String> result = stringStream
.collect(HashMap::new,
(m, e) -> {
Integer key = this.getKey(e);
if(key != 0) {
m.merge(key, e, String::concat);
}
},
Map::putAll);
您可以像这样使用成对流:
stringStream.map(x -> new Pair(getKey(x), x))
.filter(pair -> pair.left != 0) // or whatever predicate
.collect(Collectors.groupingBy(pair -> pair.left,
Collectors.mapping(pair -> pair.right, Collectors.joining())));
此代码假设简单 Pair
class 具有两个字段 left
和 right
.
像我的 StreamEx 这样的一些 third-party 库提供了额外的方法来删除样板文件:
StreamEx.of(stringStream)
.mapToEntry(this::getKey, x -> x)
.filterKeys(key -> key != 0) // or whatever
.grouping(Collectors.joining());