【问题标题】:Convert String into Map with Stream API filter and peek operators使用 Stream API 过滤器和 peek 运算符将字符串转换为地图
【发布时间】:2021-03-08 01:46:18
【问题描述】:

我有一个输入字符串,我想将它放入 HashMap。 字符串(这不是 url 参数)看起来像:source=google&date=2019-01-01&...

public Map<String, String> extract(String source) {
   return Arrays.stream(source.split("&"))
           .map(s -> s.trim().split("="))
           .peek(pairs -> pairs[0] = convert(pairs[0])
           .filter(this::isValid)
           .collect(Collectors.toMap(
                   key -> key[0],
                   value -> value[1],
                   (val1, val2) -> val2)
           );
}

private boolean isValid(String[] strings) {
        return strings.length == 2
                && !strings[0].isBlank()
                && !strings[1].isBlank();
    }

上面字符串的结果是:[source=google, date=2019-01-01, ..] 但如果字符串有空格,例如: source = google &amp; date= 2019-01-01,结果将是[ source = google, ...]。 我想删除空格,所以我添加:

 .map(s -> s.trim().split("="))
 .peek(this::removeWhiteSpaces)


 private void removeWhiteSpace(String [] strings) {
        strings[0] = strings[0].trim();
        strings[1] = strings[1].trim();
        string[0] = convert(string[0]);
    }

它工作正常,但现在如果不能将 String 拆分为具有 2 个元素的数组,如下所示:source campaign&amp;date... 它将抛出 ArrayIndexOutOfBoundException,因为 string[1] 不存在。所以我把filter移到peek上方:

.filter(this::isValid)
.peek(pairs -> pairs[0] = convert(pairs[0])
         

现在 String source campaign&amp;date... 不会通过过滤器,但这里还有一个问题。 方法convert 可以返回空字符串“”,我应该过滤它们。这就是为什么 filter 在 peek 运算符之后。我可以用两个过滤器解决它,如下所示:

.map(s -> s.trim().split("="))
.filter(strings -> strings.length==2)
.peek(this::removeWhiteSpaces)
.filter(strings -> !strings[0].isBlank() && !strings[1].isBlank())
.collect(..)

但是我可以用一个过滤器做到这一点吗?可能我的流链一点都不好?

UPD convert方法:

private String convert(String string) {
   return conversionTable.getOrDefault(string, ""); //map with key/values
}

【问题讨论】:

  • 您想删除结果中的任何空格还是只删除前导空格?
  • whitespace this is a string whitespace 应该是 this a string。同时用于键和值(由 = 分隔)。如此领先和落后。
  • 你说结果会是[ source = google, ...]为什么不是[source=google,...
  • 你在找return Arrays.stream(source.split("&amp;")) .map(s -&gt; Arrays.stream(s.split("=")) .map(String::trim) .toArray(String[]::new) ).filter(this::isValid) .collect(Collectors.toMap(x -&gt; x[0], x -&gt; x[1]));
  • is peek really only for debugging? 已在五年前被要求回答 那个 问题。除此之外,你为什么不首先使用.split("\\s*&amp;\\s*").split("\\s*=\\s*"),而不是在额外的操作中删除空白?

标签: java string java-stream


【解决方案1】:

使用@Holger 建议去除空格,您只需要处理长度为 0、1 或 2 的输入数据的 String[],这些输入数据由过滤器处理并更改为收集器 value -&gt; value.length &lt; 2 ? "" : value[1]

public Map<String, String> extract(String source) {
    return Arrays.stream(source.split("\\s*&\\s*"))
            .map(s -> s.trim().split("\\s*=\\s*")) // String[0..2] based on your input
            //.peek(a -> System.out.println(Arrays.toString(a)))
            .filter(a -> a.length > 0 && a[0].length() > 0)
            .collect(Collectors.toMap(
                    key -> key[0],
                    value -> value.length < 2 ? "" : value[1],
                    (val1, val2) -> val2)
            );

}
    System.out.println("1="+u.extract("      &source=google&date=2019-01-01&name1=value1&=&&       &  =   &flag2&arg=v"));
    System.out.println("2="+u.extract("   source = google&date=2019-01-01&flag3  & name1 = value1&flag2 &arg=v&flag4"));

以上内容去除空白名称并打印:

1={date=2019-01-01, arg=v, flag2=, source=google, name1=value1}
2={date=2019-01-01, flag4=, arg=v, flag3=, flag2=, source=google, name1=value1}

如果您正在映射键并剥离无法识别的条目,您可以在 collect() 之前添加:

 .map(this::convert)
 .filter(Objects::nonNull)

convert 是:

private String[] convert(String[] arr) {
    arr[0] = conversionTable.getOrDefault(arr[0], null);

    return arr[0] != null ? arr : null;
}

【讨论】:

  • 感谢您建议使用另一个正则表达式进行拆分,但我还需要转换数组的第一个元素,然后检查转换后的元素是否为空。
  • 我在上次编辑中添加的过滤器应该处理诸如“&=& = &”中的空白
  • 我的convert 方法从数组中获取第一个元素,例如:source=google(拆分后的第一个元素是source)。方法应该返回ga:source,然后检查ga:source是否为空,因为如果转换字符串的方法不能转换它,则返回空字符串。例如sour=googlesourc 无效,则convert 方法返回empty string here,则过滤器应检查此新字符串并跳过此元素。
  • 所以在检查数组中的第一个元素是否为空之前,我应该转换它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-24
  • 2011-07-04
  • 1970-01-01
  • 1970-01-01
  • 2014-09-03
相关资源
最近更新 更多