【问题标题】:Print Multivalued Map and format output using Stream API使用 Stream API 打印多值映射和格式输出
【发布时间】:2019-09-19 16:29:46
【问题描述】:

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

问题是我需要将 List 的第一个值分成两个,打印它们,然后打印第二个。然后,我需要应用某些格式,所以输出应该是这样的:

xxxx|yyy| zzz

xxx |yy | zzz

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

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

【问题讨论】:

  • 到目前为止你尝试了什么?

标签: java dictionary java-stream


【解决方案1】:

是的,它可以使用 Stream API 使用一对一的方式完成,但在这种情况下,您将不得不编写一些自定义类/es 来保存来自流中间操作的数据。这些自定义类(或 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

【讨论】:

    【解决方案2】:

    首先,据我了解,您不会在地图上进行操作,而只能使用此地图中的列表。 因此可以在第一次操作中提取列表并拆分字符串。

    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 只针对您的域,之后其余代码都是通用的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      相关资源
      最近更新 更多