我有Map<String, Set<String>> myMap;
结构:
{
"key1" : ["val1","val2","val3"]
"key2" : ["val4","val5","val6"]
"key3" : ["val7","val8"]
}
我可以使用Collectors.joining
:
val1 key1 val2 key1 val3
val4 key2 val5 key2 val6
val7 key3 val8
但全局我还需要将所有值组合在一个字符串中:
"val1 key1 val2 key1 val3 key2 val4 key2 val5 key2 val6 key3 val7 key3 val8"
^ ^
其中值由正确值的键连接。
是的,我能以强制性的方式实现这个目标,但我问我如何用流api实现这个目标。
答案 0 :(得分:2)
另一种方法是flatMap
两次,并构建一个键值字符串管道:
String s = myMap.entrySet().stream().flatMap(
e -> e.getValue().stream().flatMap(val -> Stream.of(e.getKey(), val))
).collect(Collectors.joining(" "));
System.out.println(s);
会给你:
key1 val1 key1 val2 key1 val3 key2 val4 key2 val5 key2 val6 key3 val7 key3 val8
必须跳过第一个键字符串才能获得预期的输出。
String s = myMap.entrySet().stream().flatMap(
e -> e.getValue().stream().flatMap(val -> Stream.of(e.getKey(), val))
).skip(1).collect(Collectors.joining(" "));
System.out.println(s);
val1 key1 val2 key1 val3 key2 val4 key2 val5 key2 val6 key3 val7 key3 val8
答案 1 :(得分:1)
首先,应该强调的是,只有存在已定义的遭遇顺序时,此请求才有意义,这不适用于普通的HashMap
和HashSet
。
对于具有稳定订单的地图和集合,例如LinkedHashMap
,TreeMap
及其Set
对应方,如果我们可以使用以下内容,那就太好了。
String s=myMap.entrySet().stream()
.map(e -> e.getValue().stream().collect(
()->new StringJoiner(" "+e.getKey()+" "),StringJoiner::add, StringJoiner::merge))
.collect(()->new StringJoiner(""), StringJoiner::merge, StringJoiner::merge)
.toString();
但它不起作用,因为StringJoiner::merge
将使用 left StringJoiner
的分隔符而不是 right 。
由于此行为不可配置,我们需要自己的StringJoiner
变体:
final class RightHandJoiner {
String separator;
StringBuilder content;
public RightHandJoiner(String sep) {
separator = sep;
}
public RightHandJoiner add(CharSequence next) {
if(content==null) content=new StringBuilder(next);
else content.append(separator).append(next);
return this;
}
public RightHandJoiner merge(RightHandJoiner next) {
if(next.content!=null) {
if(content==null) {
content=new StringBuilder(next.content);
separator=next.separator;
}
else content.append(next.separator).append(next.content);
}
return this;
}
public String toString() {
return content==null? "": content.toString();
}
}
这是有意简化为只为您的任务服务,例如它不支持非空前缀和后缀字符串。用这个类替换StringJoiner
,你将得到一个可行的解决方案:
String s=myMap.entrySet().stream()
.map(e -> e.getValue().stream()
.collect(() -> new RightHandJoiner(" "+e.getKey()+" "),
RightHandJoiner::add, RightHandJoiner::merge))
.collect(()->new RightHandJoiner(""), RightHandJoiner::merge, RightHandJoiner::merge)
.toString();