Java 8中将字符串拆分并存储到HashMap的模式

4
我想将以下字符串拆分并存储到HashMap中:
String currentString= "firstName-lastName-rollNum-departmentNum=firstName1-lastName1-rollNum1-departmentNum1"; 

我希望我的输出结果被存储在一个映射中,就像在连字符(-)之前的第一个字符串(firstName)和等号(=)之后的第一个字符串(firstName1),......即:

{firstName=firstName1,lastName=lastName1,rollNum=rollNum1,departmentNum=departmentNum1}

以下代码不能匹配我的模式:
Map<String,String> mapVal= null;
mapVal = Pattern.compile("\\s*=\\s*")
                .splitAsStream(currentString.trim())
                .map(s -> s.split("-", 2))
                .collect(Collectors.toMap(a -> a[0], a -> a.length>1? a[1]: ""));

一旦我分割了字符串,我不知道如何将所需的值组合在一起,如上所示。如果您不理解我的问题,我很抱歉。
提前感谢!
5个回答

7

更简单的方法是只使用标准数组的 split 方法。

String[] keyValues = currentString.split("=", 2);
String[] keys = keyValues[0].split("-");
String[] values = keyValues[1].split("-", keys.length);
Map<String, String> map = IntStream.range(0, keys.length).boxed()
        .collect(Collectors.toMap(i -> keys[i], i -> values[i]));

这里没有错误检查,但希望它能给你一个大致的想法。


3

正如这个答案所示,基于普通数组的操作可能更加简单。

但是如果您坚持使用Stream解决方案,它可能会像这样:

Map<String,String> mapVal= Stream.of(currentString)
    .map(s0 -> Arrays.stream(s0.split("\\s*=\\s*", 2))
        .map(s1 -> s1.split("-")).toArray(String[][]::new))
    .flatMap(a -> IntStream.range(0, a[0].length)
        .mapToObj(i -> new String[]{ a[0][i], i < a[1].length? a[1][i]: "" }))
    .collect(Collectors.toMap(a -> a[0], a -> a[1]));

说实话,我把这个问题留给自己去想如何将该解决方案转换为流,并且现在我看了一眼之后,我还需要更好地理解它,并且查看它是否与更通用的方法相匹配。当然,我也可以在这里看到Stream.of,但主要是考虑splitmap的思路。 - Naman
2
@nullpointer 好的,采用sprinter的解决方案,将两个currentString.split("=")表达式重构为在此之前声明的本地值,然后将所有这些步骤转换为Stream操作。由于Stream无法保存一对两个元素,您必须使用数组来保存keysvalues(二维数组类型已经有这两个变量)。在进行转换之后,重构它以使用流操作创建String[][],以不再有两个split('-')操作。然后,您就可以得到我的答案了... - Holger

2
另一个解决方案是:
String[] arr = Arrays.toString(currentString.split("="))
                     .replaceAll("[\\[\\]]", "").replaceAll(",", "-")
                     .split("-");

Map<String, String> collect = IntStream.range(0, arr.length / 2).boxed()
                 .collect(Collectors.toMap(i -> arr[i], i -> arr[i + arr.length / 2]));

这里我们首先根据=拆分字符串,然后使用.toString()从字符串中删除所有出现的][。现在,我们将,替换为-,以便可以基于-拆分生成的字符串。
第一条语句执行后,数组arr如下所示:

[firstName, lastName, rollNum, departmentNum, firstName1, lastName1, rollNum1, departmentNum1]

现在,我们只需要迭代结果数组(arr)到中点(arr.length / 2)并使用Collectors.toMap进行映射即可。

是的,他们确实有。只是我仍然觉得sprinter的解决方案更简单。 - Naman
2
@nullpointer 是的,sprinter的解决方案要简单得多。我不得不多次阅读这个字符串操作代码才明白它是一个低效的变体 String[] arr = Arrays.stream(currentString.split("=")) .flatMap(s -> Arrays.stream(s.split("-"))) .toArray(String[]::new);,而且还不正确,因为它在第一个值中插入了一个空格字符。更不用说当使用包含 '['']'',' 的不同输入值时会发生什么了... - Holger

0

另一种方式是这样的:

Pattern pattern = Pattern.compile("\\s*=\\s*");
int index = currentString.indexOf("=");
Map<Boolean, List<String>> map = pattern
            .splitAsStream(currentString.trim())
            .flatMap(s -> Stream.of(s.split("-")))
            .collect(partitioningBy(s -> currentString.indexOf(s) > index));

这一步的结果是:

{
  false=[firstName, lastName, rollNum, departmentNum],

  true=[firstName1, lastName1, rollNum1, departmentNum1]
}

然后将之前的结果转换为最终结果:

IntStream.range(0, map.get(true).size())
            .boxed()
            .collect(toMap(i -> map.get(false).get(i), i -> map.get(true).get(i)));

0
public static Map<String, String> toMap(String str) {
    String[] arr = str.split("[-=]");
    Map<String, String> map = new LinkedHashMap<>();

    for (int i = 0, j = arr.length / 2; j < arr.length; i++, j++)
        map.put(arr[i], arr[j]);

    return map;
}

1
使用 arr.length/2; 替代 j = 4; - Hadi J
没关系。我喜欢我的解决方案,因为不需要四次执行 arr.length / 2 - oleg.cherednik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接