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

12
我想把下面的字符串拆分并存储到HashMap中。
String responseString = "name~peter-add~mumbai-md~v-refNo~"; 

首先,我使用连字符 (-) 分隔字符串并将其存储到 ArrayList 中,代码如下:

 public static List<String> getTokenizeString(String delimitedString, char separator) {
    final Splitter splitter = Splitter.on(separator).trimResults();
    final Iterable<String> tokens = splitter.split(delimitedString);
    final List<String> tokenList = new ArrayList<String>();
    for(String token: tokens){
        tokenList.add(token);
    }
    return tokenList;
}
List<String> list = MyClass.getTokenizeString(responseString, "-");

然后使用以下代码将其转换为HashMap,使用流(stream)。

HashMap<String, String> = list.stream()
                          .collect(Collectors.toMap(k ->k.split("~")[0], v -> v.split("~")[1]));

由于refNo没有值,流收集器无法工作。

如果ArrayList中的元素数量是偶数,则可以正常工作。

有没有办法处理这个问题?还请建议如何使用Java 8流来完成这两个任务(我不想使用getTokenizeString()方法)。

4个回答

22

除非Splitter有任何魔法,否则getTokenizeString方法在此处已经过时。您可以将整个处理作为单个操作执行:


Map<String,String> map = Pattern.compile("\\s*-\\s*")
    .splitAsStream(responseString.trim())
    .map(s -> s.split("~", 2))
    .collect(Collectors.toMap(a -> a[0], a -> a.length>1? a[1]: ""));
通过使用正则表达式\s*-\s*作为分隔符,您将空格视为分隔符的一部分,因此隐式地修剪了条目。 在处理条目之前只进行一次初始的trim操作,以确保第一个条目之前或最后一个条目之后没有空格。
然后,在收集到Map之前,只需通过map步骤将条目拆分即可。

非常感谢您的快速有效的回答。完美运作。 - Sangam Belose
使用 split() 两次,一次用于 -,另一次用于 ~,可以吗? - Vishwa Ratna
2
@VishwaRatna 由于这是两个独立的操作,具有不同的语义,因此单独执行它们没有任何问题。您应该避免执行冗余操作,例如在原始代码中对相同输入执行了两次 split("~") - Holger

8

首先,您不必两次拆分相同的String
其次,检查数组的长度以确定给定键是否存在值。

HashMap<String, String> map= 
    list.stream()
        .map(s -> s.split("~"))
        .collect(Collectors.toMap(a -> a[0], a -> a.length > 1 ? a[1] : ""));

假设您希望在键没有对应值的情况下将键与null值一起放置。
或者,您可以跳过list变量:
HashMap<String, String> map1 = 
    MyClass.getTokenizeString(responseString, "-")
        .stream()
        .map(s -> s.split("~"))
        .collect(Collectors.toMap(a -> a[0], a -> a.length > 1 ? a[1] : ""));

感谢您的快速回复。看起来它只会在波浪线上分割,而不是连字符。还有,我该如何摆脱第一个getTokenizeString()方法? - Sangam Belose
我尝试了你的代码。它抛出了NullPointerException异常。它只适用于偶数大小的列表。 - Sangam Belose
1
@SangamBelose 这段代码假设你保留了 List<String> list = MyClass.getTokenizeString(responseString, "-"); - Eran
即使我保留 MyClass.getTokenizeString(responseString, "-");,它仍然会抛出空指针异常。它在最后一个数组值上失败了。 - Sangam Belose

1
private final String dataSheet = "103343262,6478342944, 103426540,84528784843, 103278808,263716791426, 103426733,27736529279, 
103426000,27718159078, 103218982,19855201547, 103427376,27717278645, 
103243034,81667273413";

    final int chunk = 2;
    AtomicInteger counter = new AtomicInteger();
    Map<String, String> pairs = Arrays.stream(dataSheet.split(","))
            .map(String::trim)
            .collect(Collectors.groupingBy(i -> counter.getAndIncrement() / chunk))
            .values()
            .stream()
            .collect(toMap(k -> k.get(0), v -> v.get(1)));

result:

pairs =
 "103218982" -> "19855201547"
 "103278808" -> "263716791426"
 "103243034" -> "81667273413"
 "103426733" -> "27736529279"
 "103426540" -> "84528784843"
 "103427376" -> "27717278645"
 "103426000" -> "27718159078"
 "103343262" -> "6478342944"

我们需要将每2个元素分为一组键值对,因此将列表分成2个块,(counter.getAndIncrement() / 2) 每2次击中将返回相同的数字,例如:
IntStream.range(0,6).forEach((i)->System.out.println(counter.getAndIncrement()/2));
prints:
0
0
1
1
2
2

你可以使用相同的思路将列表分成块。

1
另一种简短的方法是:
String responseString = "name~peter-add~mumbai-md~v-refNo~";
Map<String, String> collect = Arrays.stream(responseString.split("-"))
                              .map(s -> s.split("~", 2))
                              .collect(Collectors.toMap(a -> a[0], a -> a.length > 1 ? a[1] : ""));
                              System.out.println(collect);

首先,你需要根据 - 进行字符串拆分,然后像这样进行映射 map(s -> s.split("~", 2)) ,创建一个类似于 [name, peter][add, mumbai][md, v][refNo, ]Stream<String[]>,最后将其收集到 toMap 中,其中 a[0] 是键,a[1] 是值。


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