打印多值映射并使用流 API 格式化输出



这里是 Map(String, List(String((, List 包含两个具有以下模式的值:xxxx_yyy, zzz。每个键的字符串长度各不相同。

问题是我需要将列表的第一个值一分为二,打印它们,然后打印第二个值。然后,我需要应用某些格式,因此输出应如下所示:

xxxx|yyy| zzz

xxx |yy | zzz

从字符串中的最后一个符号到"|"符号的缩进应该是固定的,并且等于列表中最长字符串的长度。

是否可以使用流 API 在一行中实现它?

是的,可以使用流 API 在一行中使用一个来完成,但在这种情况下,您必须编写一些自定义类,这些类将保存来自流中间操作的数据。这些自定义类(或 Pair(将保留拆分字符串长度的最大值和最小值xxxx_yyy。此信息将用于终端操作,以打印格式的字符串。

下面的代码提供了相同的结果,但不在一个行流中。首先,它找到字符串的长度,然后格式化输出

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MultiValuedMain {
public static void main(String[] args) {
Map<String, List<String>> map = new HashMap<>();
map.put("key1", new ArrayList<String>(Arrays.asList("xxxx_yyy", "zzz")));
map.put("key2", new ArrayList<String>(Arrays.asList("xxxx_yyyy", "zzz")));
map.put("key3", new ArrayList<String>(Arrays.asList("xxxxx_yyy", "zzz")));
map.put("key4", new ArrayList<String>(Arrays.asList("xxxx_yy", "zzz")));
map.put("key5", new ArrayList<String>(Arrays.asList("xxxxxxx_yyy", "zzz")));
int xLength = map.entrySet().stream().map(stringListEntry -> stringListEntry.getValue().get(0).split("_")[0])
.mapToInt(String::length).max().orElse(0);
int yLength = map.entrySet().stream().map(stringListEntry -> stringListEntry.getValue().get(0).split("_")[1])
.mapToInt(String::length).max().orElse(0);
map.forEach((key, value) -> {
String[] arr = value.get(0).split("_");
System.out.println(arr[0] + getEmptyString(xLength - arr[0].length()) + "|"
+ arr[1] + getEmptyString(yLength - arr[1].length()) + "|" + value.get(1));
});
}
private static String getEmptyString(int length) {
StringBuilder ret = new StringBuilder();
while(length > 0) {
ret.append(" ");
length--;
}
return ret.toString();
}
}

输出:

xxxx   |yyy |zzz
xxxx   |yyyy|zzz
xxxxxxx|yyy |zzz
xxxxx  |yyy |zzz
xxxx   |yy  |zzz

首先,据我所知,您不在地图上进行操作,而只对这张地图中的列表进行操作。 因此,可以在第一次操作中提取列表并拆分字符串。

List<List<String>> listOfListOfStrings = map.values().stream()
.map(v -> Arrays.asList(v.get(0).split("_")[0], v.get(0).split("_")[1], v.get(1)))
.collect(Collectors.toList());

之后可以计算每列的最大(固定(长度。

List<Integer> maxSpacesForEachColumn = listOfListOfStrings.stream()
.map(a ->
a.stream().map(String::length).collect(Collectors.toList())
)
.reduce(Collections.nCopies(listOfListOfStrings.get(0).size(), 0), (a, v) ->
IntStream
.range(0, a.size())
.mapToObj(i -> a.get(i) > v.get(i) ? a.get(i) : v.get(i))
.collect(Collectors.toList())
);

最后,这两个集合可以组合在一起。对于右垫String.format使用:

listOfListOfStrings.stream()
.map(v -> IntStream
.range(0, maxSpacesForEachColumn.size())
.mapToObj(i ->
String.format("%1$-" + maxSpacesForEachColumn.get(i) + "s", v.get(i)))
.collect(Collectors.joining("|")))
.forEach(System.out::println);

显然它不是一行,但尝试这样做会使代码不可读。此解决方案也可能非常不可读。但是创建listOfListOfStrings仅特定于您的域,之后其余代码是通用的。

最新更新