简体   繁体   English

什么是反转嵌套 java 地图顺序的正确方法

[英]What is a proper way to reverse the order of nested java Maps

I'm trying to reverse the order of a nested Map.我正在尝试颠倒嵌套 Map 的顺序。

As there is no built-in function in Map to reverse the order and I'm out of time.由于 Map 中没有内置的 function 来反转顺序,所以我没时间了。 I tried several available methods of reversing the order posted by devs but nothing worked and also I didn't see any error.我尝试了几种可用的方法来反转开发人员发布的顺序,但没有任何效果,而且我也没有看到任何错误。 I don't know what's wrong with the code probably because I've not used Map that much and I'm relatively new to java.我不知道代码有什么问题,可能是因为我没有太多使用 Map,而且我对 java 比较陌生。

Here is the structure of the map Map<String, HashMap<String, Object>> playersDataMap = new HashMap<> ();这里是map Map<String, HashMap<String, Object>> playersDataMap = new HashMap<> ();的结构

And these are a couple of methods I copied from a website but none of them worked.这些是我从网站上复制的几种方法,但都没有奏效。 It always returns me the with the same order.它总是以相同的顺序返回给我。

    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();
    }

I also tried changing the HashMap to LinkedHashMap but no success, same results.我还尝试将 HashMap 更改为 LinkedHashMap 但没有成功,结果相同。

Please let me know what is wrong with the code.请让我知道代码有什么问题。 I'm really out of time otherwise I would have read the docs of Maps before posting or even implementation.我真的没时间了,否则我会在发布甚至实施之前阅读地图文档。 Your help will be greatly appreciated.对你的帮助表示感谢。 thanks谢谢

Here is the example of what I'm trying to implement这是我正在尝试实现的示例

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"));
}

Results: "Debug: player key: x9 pointsScored: 90" "Debug: player key: x390 pointsScored: 390" "Debug: player key: x30 pointsScored: 30"...结果:“调试:播放器密钥:x9 点得分:90” “调试:播放器密钥:x390 点得分:390” “调试:播放器密钥:x30 点得分:30”...

Expected output: "Debug: player key: x390 pointsScored: 390" "Debug: player key: x380 pointsScored: 380"...预期 output:“调试:播放器密钥:x390 点得分:390”“调试:播放器密钥:x380 点得分:380”...

If all you want to do is reverse your current map, then this will do it.如果您想要做的就是反转您当前的 map,那么就可以了。

Here is the test Map这里是测试 Map


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);

}

Here is the comparator.这里是比较器。 Note that this depends on x being the same for keys in the enclosing map.请注意,这取决于x对于封闭 map 中的键是否相同。

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

And the sorting和排序

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"));
    }
}

Prints印刷

...
...
...
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 
...
...
...

Not certain why you are using a Map of Maps, though.不过,不确定您为什么要使用地图的 Map。 Is the key to the outerMap any importance (Like a team designator perhaps?) externalMap 的关键是否重要(也许像团队指示符?)

[Original answer] [原答案]

Your approach of using a Map can be problematic.您使用Map的方法可能会出现问题。 You should create a new type and use a List of the new type.您应该创建一个新类型并使用新类型的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);
    }
}

[Update] [更新]

You can use Map in the following way:您可以通过以下方式使用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"));
        }
    }
}

Output: Output:

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

Both the above answers worked but to some extent.上述两个答案都有效,但在某种程度上。 They didn't work on a mixed string.他们没有在混合字符串上工作。

So what I did is replaced the HashMap to linkedHashMap.所以我所做的就是将 HashMap 替换为linkedHashMap。 Then I added the keySet of that Map to newly created List of strings and reversed it using Collections.reverse then iterated through that list and added the reserved order into a new Map.然后我将该 Map 的 keySet 添加到新创建的字符串列表中,并使用 Collections.reverse 将其反转,然后遍历该列表并将保留的顺序添加到新的 Z46F3EA056CAA3126B91F3F70BEEA068C 中。

Here is the code of my invert function.这是我的反相 function 的代码。

Important , the argument i passed as a playersDataMap is a linkedHashMap.重要的是,我作为 playerDataMap 传递的参数是一个linkedHashMap。 For further explanation on LinkedHashMap please go to the following link https://beginnersbook.com/2013/12/linkedhashmap-in-java/ .有关 LinkedHashMap 的进一步说明,请 go 到以下链接https://beginnersbook.com/2013/12/linkedhashmap-in-java/ thanks!谢谢!

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM