我需要帮助解决这个问题,我有两个字符串
String s1 = "Mohan";
String s2 = "1234567";
我需要输出为
"M1o2h3a4n567"
就像 s1 第一个字符然后 s2 第一个字符。
如何使用 java8 流 API 解决这个问题?
我将两个字符串转换为一个列表,然后在流API中尝试使用reduce,但我知道这不是正确的解决方案。
如果你确实想使用流,你可以构造一个较短字符串索引的流,并将每个索引映射到一个由字符
s1.charAt(i)
和 s2.charAt(i)
组成的字符串,用 Collectors.joining()
将它们连接起来,然后添加任何内容较长字符串的左侧。
var shorterLength = Math.min(s1.length(), s2.length());
var result = IntStream.range(0, shorterLength).mapToObj(
i -> s1.charAt(i) + String.valueOf(s2.charAt(i))
).collect(Collectors.joining())
+ s1.substring(shorterLength) + s2.substring(shorterLength);
也就是说,这会创建很多中间字符串。它为每一对字符创建一个新的字符串对象。
我宁愿不使用流,而只是使用
StringBuilder
命令式地执行此操作。没那么长了。
var sb = new StringBuilder();
for (int i = 0 ; i < shorterLength ; i++) {
sb.append(s1.charAt(i)).append(s2.charAt(i));
}
if (s1.length() > shorterLength) {
sb.append(s1.substring(shorterLength));
} else if (s2.length() > shorterLength) {
sb.append(s2.substring(shorterLength));
}
// or just
// sb.append(s1.substring(shorterLength)).append(s2.substring(shorterLength));;
// if you don't care about creating an extra substring
var result = sb.toString();
嗯,有很多选择,每种都有优点和缺点。
这是另一种方法,使用
IntStream
和 StringBuilder
:
String result = IntStream.range(0, Math.max(s1.length(), s2.length()))
.collect(
StringBuilder::new,
(sb, i) -> {
if (i < s1.length()) {
sb.append(s1.charAt(i));
}
if (i < s2.length()) {
sb.append(s2.charAt(i));
}
},
StringBuilder::append
)
.toString();
这里发生的是,我们循环(使用
IntStream
)两个字符串中最大的一个字符串的所有索引(使用max(s1.length(), s2.length())
)。
然后我们收集到一个
StringBuilder
中,如果存在则添加s1
中的字符,然后对s2
进行同样的操作。
请注意,此代码不使用任何中间子字符串。
但是,我认为 ol' skool for 或 foreach 循环与使用流一样好。