【问题标题】:What is a proper way to reverse the order of nested java Maps什么是反转嵌套java Maps顺序的正确方法
【发布时间】:2020-05-05 10:40:29
【问题描述】:

我正在尝试反转嵌套 Map 的顺序。

由于 Map 中没有内置函数来反转顺序,所以我没时间了。我尝试了几种可用的方法来反转开发人员发布的顺序,但没有任何效果,而且我也没有看到任何错误。我不知道代码有什么问题,可能是因为我没有太多使用 Map,而且我对 java 比较陌生。

这是地图的结构 Map<String, HashMap<String, Object>> playersDataMap = new HashMap<> ();

这些是我从网站上复制的几种方法,但都没有奏效。它总是以相同的顺序返回给我。

    public static <K extends Comparable, V> Map<K,V> sortByKeys(Map<K,V> map)
    {
        Map<K, V> treeMap = new TreeMap<>(new Comparator<K>() {
            @Override
            public int compare(K a, K b) {
                return b.compareTo(a);
            }
        });

        treeMap.putAll(map);

        return treeMap;
    }

    public static <K, V> Map<K,V> sortByTreeMap(Map<K,V> unsortedMap)
    {
        // construct a TreeMap from given Map and return a reverse order
        // view of the mappings contained in this map
        return new TreeMap<>(unsortedMap).descendingMap();
    }

我也尝试将 HashMap 更改为 LinkedHashMap 但没有成功,结果相同。

请告诉我代码有什么问题。我真的没时间了,否则我会在发布甚至实施之前阅读地图文档。对你的帮助表示感谢。谢谢

这是我正在尝试实现的示例

Map<String, HashMap<String, Object>> playersDataMap = new LinkedHashMap<> ();
for (int i = 1; i < 40; i++)
{
    HashMap<String, Object> playerMap = new HashMap<> ();
    playerMap.put ("name", "abc"+i);
    playerMap.put ("pointsScored", i * 10);
    playersDataMap.put ("x"+i, playerMap);
}


Map<String, HashMap<String, Object>> inversedPlayerDataMap = new LinkedHashMap<>();
inversedPlayerDataMap = new TreeMap<>(Comparator.reverseOrder());
inversedPlayerDataMap.putAll(playersDataMap);

for (Map.Entry<String, HashMap<String, Object>> player : inversedPlayerDataMap.entrySet ())
{
    System.out.printf ("Debug: player key: %s playerValueScore: %s \n", player.getKey (), player.getValue ().get("pointsScored"));
}

结果:“调试:播放器密钥:x9 点得分:90” “调试:播放器密钥:x390 点得分:390” “调试:播放器密钥:x30 点得分:30”...

预期输出:“调试:播放器密钥:x390 点得分:390”“调试:播放器密钥:x380 点得分:380”...

【问题讨论】:

  • 如果您测试了上述 2 种方法,那么您的期望很可能是有问题的。请添加测试数据和预期输出
  • 另外我正在以这种方式创建排序地图的新参考变量 Map> inversedPlayerDataMap = sortByKeys (playersDataMap);希望没有问题
  • 感谢@ernest_k,正如我已经说过的,我对 java 比较陌生,所以我可能在上面真的很奇怪。你知道有什么更快的方法来解决这个问题吗?在使用测试数据之前...
  • @Voodoo 在第一个代码 sn-p
  • 你有 String 键,字符串的自然顺序是它们的字典顺序。换句话说,"x9" &gt; "x390"。你需要像Comparator.comparingInt((String s) -&gt; Integer.parse(s.substring(1))).reversed() 这样的东西来按数值降序排序。但是,当键具有更复杂的模式(即单词和数字的混合)时,提供所需顺序的比较器并非易事。

标签: java java-8 hashmap java-9


【解决方案1】:

如果您只想反转您当前的地图,那么就可以了。

这是测试地图


for (int i = 10; i < 300; i += 10) {

    playerMap = new HashMap<String, Object>();
    playerMap.put("name", "person" + (i / 10));
    playerMap.put("pointsScored", i);

    playersDataMap.put("x" + i, playerMap);

}

这里是比较器。请注意,这取决于 x 是否与封闭映射中的键相同。

Comparator<String> comp = Comparator
        .comparing(String::length)
        .thenComparing(String::compareTo)
        .reversed();

还有排序

inversedPlayerDataMap = new TreeMap<>(comp);
inversedPlayerDataMap.putAll(playersDataMap);


for (Map.Entry<String, HashMap<String, Object>> player : inversedPlayerDataMap
                .entrySet()) {
    System.out.printf(
                    "Debug: player key: %s playerValueScore: %s \n",
                    player.getKey(),
                    player.getValue().get("pointsScored"));
    }
}

打印

...
...
...
Debug: player key: x130 playerValueScore: 130 
Debug: player key: x120 playerValueScore: 120 
Debug: player key: x110 playerValueScore: 110 
Debug: player key: x100 playerValueScore: 100 
Debug: player key: x90 playerValueScore: 90 
Debug: player key: x80 playerValueScore: 80 
...
...
...

不过,不确定您为什么要使用 Map of Maps。 outerMap 的关键是否重要(也许像团队指示符?)

【讨论】:

  • 是的,这很重要。这是玩家的 id。
  • @Holger 你能详细说明一下吗?
  • 我遇到了“无法解决条目”的异常。这是哪个班?
  • 忽略我最后的回答。 @Holger 是正确的(通常)。请参阅我的更新答案。
  • 感谢任何人,感谢您的投票。
【解决方案2】:

[原答案]

您使用Map 的方法可能会出现问题。您应该创建一个新类型并使用新类型的List

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class MyType {
    String playerKey;
    Map<String, Object> map = new HashMap<String, Object>();

    public MyType(String id, Map<String, Object> map) {
        this.playerKey = id;
        this.map = map;
    }

    public String getPlayerKey() {
        return playerKey;
    }

    @Override
    public String toString() {
        return "playerKey=" + playerKey + ", pointsScored=" + map.get("pointsScored");
    }
}

public class Main {
    public static void main(String[] args) {
        List<MyType> playersData = new ArrayList<MyType>();
        playersData.add(new MyType("x1", Map.of("name", "john", "pointsScored", 50)));
        playersData.add(new MyType("x11", Map.of("name", "harry", "pointsScored", 55)));
        playersData.add(new MyType("x2", Map.of("name", "tina", "pointsScored", 60)));
        playersData.add(new MyType("y1", Map.of("name", "richard", "pointsScored", 60)));
        playersData.add(new MyType("y12", Map.of("name", "kim", "pointsScored", 45)));
        playersData.add(new MyType("y3", Map.of("name", "karen", "pointsScored", 65)));
        System.out.println("Orinally:");
        playersData.stream().forEach(System.out::println);
        playersData.sort(new Comparator<MyType>() {
            @Override
            public int compare(MyType t1, MyType t2) {
                String s1 = t1.getPlayerKey();
                String s2 = t2.getPlayerKey();

                int compVal;
                int n1 = 0, n2 = 0;
                String sn1 = "", sn2 = "";

                // Pattern to find a sequence of digits
                Pattern pattern = Pattern.compile("\\d+");
                Matcher matcher;

                matcher = pattern.matcher(s1);
                if (matcher.find()) {
                    // Number from first string
                    sn1 = matcher.group();
                    n1 = Integer.valueOf(sn1);
                }

                matcher = pattern.matcher(s2);
                if (matcher.find()) {
                    // Number from first string
                    sn2 = matcher.group();
                    n2 = Integer.valueOf(sn2);
                }

                // Compare the string part
                compVal = s2.substring(0, s2.indexOf(sn2)).compareTo(s1.substring(0, s1.indexOf(sn1)));

                // If string parts are same, compare the number parts
                if (compVal == 0 && n1 != 0 && n2 != 0) {
                    compVal = Integer.compare(n2, n1);
                }
                return compVal;
            }
        });

        System.out.println("\nSorted in reversed order of playerKey:");
        playersData.stream().forEach(System.out::println);
    }
}

[更新]

您可以通过以下方式使用Map

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 
 * Comparator to compare alphanumeric words in the form of LETTERS+DIGITs e.g.
 * A1, ABC123 etc.
 *
 */
class MyComparator implements Comparator<String> {

    @Override
    public int compare(String s1, String s2) {

        int compVal;
        int n1 = 0, n2 = 0;
        String sn1 = "", sn2 = "";

        // Pattern to find a sequence of digits
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher;

        matcher = pattern.matcher(s1);
        if (matcher.find()) {
            // Number from first string
            sn1 = matcher.group();
            n1 = Integer.valueOf(sn1);
        }

        matcher = pattern.matcher(s2);
        if (matcher.find()) {
            // Number from first string
            sn2 = matcher.group();
            n2 = Integer.valueOf(sn2);
        }

        // Compare the string part
        compVal = s2.substring(0, s2.indexOf(sn2)).compareTo(s1.substring(0, s1.indexOf(sn1)));

        // If string parts are same, compare the number parts
        if (compVal == 0 && n1 != 0 && n2 != 0) {
            compVal = Integer.compare(n2, n1);
        }
        return compVal;
    }
}

public class Main {
    public static void main(String[] args) {
        Map<String, HashMap<String, Object>> playersDataMap = new HashMap<>();
        for (int i = 1; i <= 10; i++) {
            HashMap<String, Object> playerMap = new HashMap<>();
            playerMap.put("name", "abc" + i);
            playerMap.put("pointsScored", i * 10);
            playersDataMap.put("x" + i, playerMap);
        }

        Map<String, HashMap<String, Object>> inversedPlayerDataMap = new TreeMap<>(new MyComparator());
        inversedPlayerDataMap.putAll(playersDataMap);
        for (Map.Entry<String, HashMap<String, Object>> entry : inversedPlayerDataMap.entrySet()) {
            System.out
                    .println("playerKey=" + entry.getKey() + ", pointsScored=" + entry.getValue().get("pointsScored"));
        }
    }
}

输出:

playerKey=x10, pointsScored=100
playerKey=x9, pointsScored=90
playerKey=x8, pointsScored=80
playerKey=x7, pointsScored=70
playerKey=x6, pointsScored=60
playerKey=x5, pointsScored=50
playerKey=x4, pointsScored=40
playerKey=x3, pointsScored=30
playerKey=x2, pointsScored=20
playerKey=x1, pointsScored=10

【讨论】:

  • 您能否根据您的实现更新最后一个示例。因为有一些限制,所以主要的 playerDataMap 是 Map> playerDataMap = new HashMap ();
  • 我会在我尝试时告诉你。现在,我正在尝试其他一些方法
  • @waleed - 我已更新我的答案以使用Map&lt;String, HashMap&lt;String, Object&gt;&gt;。我希望,它满足您的要求。
  • 谢谢@Arvind。我已经使用了上面的答案,它按预期工作。但再次感谢您的贡献。
  • @waleed - 只是一个问题,按照相反的顺序,您希望x10 还是x2 先出现?如果您希望 x10 以相反的顺序出现在 x2 之前,则此答案满足此要求。
【解决方案3】:

以上两个答案都有效,但在某种程度上。他们不适用于混合字符串。

所以我所做的就是将 HashMap 替换为linkedHashMap。然后我将该 Map 的 keySet 添加到新创建的字符串列表中,并使用 Collections.reverse 对其进行反转,然后遍历该列表并将保留的顺序添加到新 Map 中。

这是我的反转函数的代码。

重要,我作为playersDataMap 传递的参数是linkedHashMap。有关 LinkedHashMap 的进一步说明,请访问以下链接 https://beginnersbook.com/2013/12/linkedhashmap-in-java/。谢谢!

public static Map<String, HashMap<String, Object>> invertMapUsingList (Map<String, HashMap<String, Object>> playersDataMap)
{
        Map<String, HashMap<String, Object>> inversedPlayerDataMap = new LinkedHashMap<> ();
        List<String> reverseOrderedKeys = new ArrayList<String>(playersDataMap.keySet());
        Collections.reverse(reverseOrderedKeys);
        for (String key : reverseOrderedKeys)
        {
            inversedPlayerDataMap.put (key, playersDataMap.get(key));
        }

        return inversedPlayerDataMap;
}

【讨论】:

  • 你应该使用TreeMapComparator,就像大家告诉你的那样。
  • 感谢您的建议。您能否详细说明此解决方案有什么问题?你有没有读过上面所有的 cmets 知道为什么我最终得到了这个解决方案。
  • 我也尝试使用 Comparator 但没有成功。当我有不可比较的字符串时,它不起作用。例如("asdfhouoweiu0sdf", jasdfjd-f4sdjljfasfj, "dsajfkjh-sadj3df")
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-10
  • 2020-06-14
  • 2020-09-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多