如何使用delimeter连接字符串,在java8函数样式中连接内部级别的字符串

时间:2016-04-28 14:04:36

标签: functional-programming java-8 java-stream

我有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实现这个目标。

2 个答案:

答案 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)

首先,应该强调的是,只有存在已定义的遭遇顺序时,此请求才有意义,这不适用于普通的HashMapHashSet

对于具有稳定订单的地图和集合,例如LinkedHashMapTreeMap及其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();