【问题标题】:Display HashMap content in tree view在树视图中显示 HashMap 内容
【发布时间】:2022-06-10 18:26:46
【问题描述】:

我需要您的帮助,因为我找不到 Java 中的解决方案来解决我的问题。

我在对象LinkedHashMap<String, String>中存储了这个内容:

TAG1.TAG2.TAG11 : value1
TAG1.TAG2.TAG12 : value2
TAG1.TAG2.TAG3.TAG131 : value3
TAG1.TAG2.TAG3.TAG132 : value4
TAG1.TAG2.TAG3.TAG133 : value5
TAG1.TAG2.TAG3.TAG134 : value6
TAG1.TAG4.TAG5.TAG21 : value7
TAG1.TAG4.TAG5.TAG22 : value8
TAG1.TAG4.TAG5.TAG23 : value9
TAG6 : value10

如果标签有 2 个或更多孩子,我需要显示孩子的列表。 这是预期的结果:

TAG1.TAG2
    TAG11 : value1
    TAG12 : value2
TAG1.TAG2.TAG3
    TAG131 : value3
    TAG132 : value4
    TAG133 : value5
    TAG134 : value6
TAG1.TAG4.TAG5
    TAG21 : value7
    TAG22 : value8
    TAG23 : value9
TAG6 : value10

【问题讨论】:

  • 你能展示一下你最初的尝试吗?
  • 我没有找到正确的算法来启动某事。

标签: java string algorithm hashmap treeview


【解决方案1】:

这个问题最难的部分是在生成的Map 中找到所有可能的分组依据。

这基本上转换为查找每个键的最长子字符串,该子字符串与每个其他键的开头匹配,如果没有子字符串与任何其他键的开头匹配,则应收集该键本身并将其用作结果映射中的键。

使用新密钥创建Set 后,问题很容易解决。事实上,它可以简化为输入映射条目的流,只需应用一个操作:collect(Collectors.toMap())。在此操作中,每个条目的值通过新的Set 的一个键使用原始键进行映射;而如果我们排除一些字符串格式,这些值几乎保持不变。

这是一个详细的 cmets 实现,逐步解释整个逻辑:

public class Main {
    public static void main(String[] args) {
        LinkedHashMap<String, String> map = new LinkedHashMap<>(Map.of(
                "TAG1.TAG2.TAG11", "value1",
                "TAG1.TAG2.TAG12", "value2",
                "TAG1.TAG2.TAG3.TAG131", "value3",
                "TAG1.TAG2.TAG3.TAG132", "value4",
                "TAG1.TAG2.TAG3.TAG133", "value5",
                "TAG1.TAG2.TAG3.TAG134", "value6",
                "TAG1.TAG4.TAG5.TAG21", "value7",
                "TAG1.TAG4.TAG5.TAG22", "value8",
                "TAG1.TAG4.TAG5.TAG23", "value9",
                "TAG6", "value10"
        ));

        //Queue with the input map's keys. These keys are sorted by length in descending order (from the longest to the shortest)
        PriorityQueue<String> queue = new PriorityQueue<>(Comparator.comparingInt(String::length).reversed());
        queue.addAll(map.keySet());

        //Using a set to have unique keys (no duplicates) to group by in the resulting map
        Set<String> newKeys = new HashSet<>();

        //Checking for each key if its largest substring is equal to any other key's beginning:
        //  - if it does, then the substring is collected as a key to group by within the final map
        //
        //  - if it doesn't, then another substring is generated from the previous substring until a matching value is found.
        //          If no value is found, then the key is collected entirely for the resulting map.
        while (!queue.isEmpty()) {
            String key = queue.poll();

            //This loop keeps creating substrings of the current key until:
            //  - the substring matches another key's beginning
            //  - or no more substrings can be generated
            int lastIndex = key.lastIndexOf(".");
            while (lastIndex > 0) {

                //Checking if the substring matches the beginning of any key except the current one
                String subStr = key.substring(0, lastIndex);
                if (map.keySet().stream().anyMatch(s -> !s.equals(key) && s.startsWith(subStr))) {

                    //If a match is found then the current substring is added to the set and the substring iteration is interrupted
                    newKeys.add(key.substring(0, lastIndex));
                    break;
                }

                //Creating a new substring from the previous substring if no match has been found
                lastIndex = key.substring(0, lastIndex).lastIndexOf(".");
            }

            //If no substrings of the current key matches the beginning of any other key, then the current key is collected
            if (lastIndex < 0) {
                newKeys.add(key);
            }
        }

        //Creating the resulting map
        Map<String, List<String>> mapRes = map.entrySet().stream()
                .collect(Collectors.toMap(
                        entry -> {
                            //Looking for the longest newKey which matches the beginning of the current entry's key.
                            //The reason why we need the longest match (i.e. the most accurate) is because some elements
                            //may share the same parents but be on different levels, for example the values 3, 4, 5 and 6
                            //have a key whose beginning matches both "TAG1.TAG2" and "TAG1.TAG2.TAG3", but only the longest
                            //match is actually the right one.
                            return newKeys.stream().filter(s -> entry.getKey().startsWith(s)).max(Comparator.comparingInt(String::length)).orElseThrow(() -> new RuntimeException("No key found"));
                        },
                        entry -> {
                            //Retrieving, like above, the newKey that will be used to map the current value
                            String newKey = newKeys.stream().filter(s -> entry.getKey().startsWith(s)).max(Comparator.comparingInt(String::length)).orElseThrow(() -> new RuntimeException("No key found"));

                            //If the newKey and the current key are equal then a List with the current value is returned
                            if (newKey.equals(entry.getKey())) {
                                return new ArrayList<>(List.of(entry.getValue()));
                            } else {    //If the newKey is a substring of the current key then the rest of the current key is added to the value
                                return new ArrayList<>(List.of(entry.getKey().substring(newKey.length() + 1) + " : " + entry.getValue()));
                            }
                        },
                        //Handling colliding cases by merging the lists together
                        (list1, list2) -> {
                            list1.addAll(list2);
                            return list1;
                        }
                ));

        //Printing the resulting map
        for (Map.Entry<String, List<String>> entry : mapRes.entrySet()) {
            System.out.println(entry.getKey());
            for (String value : entry.getValue()) {
                System.out.println("\t" + value);
            }
        }
    }
}

输出

TAG1.TAG4.TAG5
    TAG22 : value8
    TAG21 : value7
    TAG23 : value9
TAG1.TAG2
    TAG12 : value2
    TAG11 : value1
TAG6
    value10
TAG1.TAG2.TAG3
    TAG134 : value6
    TAG133 : value5
    TAG132 : value4
    TAG131 : value3

【讨论】:

    猜你喜欢
    • 2016-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-10
    • 2018-09-21
    • 2014-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多