什么是将嵌套的Java Map顺序反转的正确方法

huangapple go评论76阅读模式
英文:

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

问题

我正在尝试颠倒嵌套映射的顺序。

由于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)
{
    // 从给定的Map构造一个TreeMap,并返回包含在此Map中的映射的反向顺序视图
    return new TreeMap<>(unsortedMap).descendingMap();
}

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

请告诉我代码有什么问题。我真的没有时间,否则我会在发布之前阅读Maps的文档,甚至进行实现。您的帮助将不胜感激。谢谢

这是我尝试实现的示例

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

结果: "Debug: player key: x9 playerValueScore: 90" "Debug: player key: x390 playerValueScore: 390" "Debug: player key: x30 playerValueScore: 30" ...

预期输出: "Debug: player key: x390 playerValueScore: 390" "Debug: player key: x380 playerValueScore: 380" ...

英文:

I'm trying to reverse the order of a nested Map.

As there is no built-in function in Map to reverse the order and I'm out of time. 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.

Here is the structure of the map
Map&lt;String, HashMap&lt;String, Object&gt;&gt; playersDataMap = new HashMap&lt;&gt; ();

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 &lt;K extends Comparable, V&gt; Map&lt;K,V&gt; sortByKeys(Map&lt;K,V&gt; map)
    {
        Map&lt;K, V&gt; treeMap = new TreeMap&lt;&gt;(new Comparator&lt;K&gt;() {
            @Override
            public int compare(K a, K b) {
                return b.compareTo(a);
            }
        });

        treeMap.putAll(map);

        return treeMap;
    }

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

I also tried changing the HashMap to LinkedHashMap but no success, same results.

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&lt;String, HashMap&lt;String, Object&gt;&gt; playersDataMap = new LinkedHashMap&lt;&gt; ();
for (int i = 1; i &lt; 40; i++)
{
    HashMap&lt;String, Object&gt; playerMap = new HashMap&lt;&gt; ();
    playerMap.put (&quot;name&quot;, &quot;abc&quot;+i);
    playerMap.put (&quot;pointsScored&quot;, i * 10);
    playersDataMap.put (&quot;x&quot;+i, playerMap);
}


Map&lt;String, HashMap&lt;String, Object&gt;&gt; inversedPlayerDataMap = new LinkedHashMap&lt;&gt;();
inversedPlayerDataMap = new TreeMap&lt;&gt;(Comparator.reverseOrder());
inversedPlayerDataMap.putAll(playersDataMap);

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

Results: "Debug: player key: x9 pointsScored: 90" "Debug: player key: x390 pointsScored: 390" "Debug: player key: x30 pointsScored: 30" ...

Expected output: "Debug: player key: x390 pointsScored: 390" "Debug: player key: x380 pointsScored: 380" ...

答案1

得分: 2

如果你只想要做的是将你当前的映射进行反转,那么这将实现这个目的。

以下是测试映射


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

不过,我不确定为什么你要使用映射的映射。外部映射的键是否重要(例如可能是一个团队的标识符)?

英文:

If all you want to do is reverse your current map, then this will do it.

Here is the test Map


for (int i = 10; i &lt; 300; i += 10) {
			
	playerMap = new HashMap&lt;String, Object&gt;();
	playerMap.put(&quot;name&quot;, &quot;person&quot; + (i / 10));
	playerMap.put(&quot;pointsScored&quot;, i);
			
	playersDataMap.put(&quot;x&quot; + i, playerMap);
			
}

Here is the comparator. Note that this depends on x being the same for keys in the enclosing map.

Comparator&lt;String&gt; comp = Comparator
		.comparing(String::length)
		.thenComparing(String::compareTo)
		.reversed();

And the sorting

inversedPlayerDataMap = new TreeMap&lt;&gt;(comp);
inversedPlayerDataMap.putAll(playersDataMap);
		

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

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. Is the key to the outerMap any importance (Like a team designator perhaps?)

答案2

得分: 0

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:

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
英文:

[Original answer]

Your approach of using a Map can be problematic. You should create a new type and use a List of the new type.

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&lt;String, Object&gt; map = new HashMap&lt;String, Object&gt;();
public MyType(String id, Map&lt;String, Object&gt; map) {
this.playerKey = id;
this.map = map;
}
public String getPlayerKey() {
return playerKey;
}
@Override
public String toString() {
return &quot;playerKey=&quot; + playerKey + &quot;, pointsScored=&quot; + map.get(&quot;pointsScored&quot;);
}
}
public class Main {
public static void main(String[] args) {
List&lt;MyType&gt; playersData = new ArrayList&lt;MyType&gt;();
playersData.add(new MyType(&quot;x1&quot;, Map.of(&quot;name&quot;, &quot;john&quot;, &quot;pointsScored&quot;, 50)));
playersData.add(new MyType(&quot;x11&quot;, Map.of(&quot;name&quot;, &quot;harry&quot;, &quot;pointsScored&quot;, 55)));
playersData.add(new MyType(&quot;x2&quot;, Map.of(&quot;name&quot;, &quot;tina&quot;, &quot;pointsScored&quot;, 60)));
playersData.add(new MyType(&quot;y1&quot;, Map.of(&quot;name&quot;, &quot;richard&quot;, &quot;pointsScored&quot;, 60)));
playersData.add(new MyType(&quot;y12&quot;, Map.of(&quot;name&quot;, &quot;kim&quot;, &quot;pointsScored&quot;, 45)));
playersData.add(new MyType(&quot;y3&quot;, Map.of(&quot;name&quot;, &quot;karen&quot;, &quot;pointsScored&quot;, 65)));
System.out.println(&quot;Orinally:&quot;);
playersData.stream().forEach(System.out::println);
playersData.sort(new Comparator&lt;MyType&gt;() {
@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 = &quot;&quot;, sn2 = &quot;&quot;;
// Pattern to find a sequence of digits
Pattern pattern = Pattern.compile(&quot;\\d+&quot;);
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 &amp;&amp; n1 != 0 &amp;&amp; n2 != 0) {
compVal = Integer.compare(n2, n1);
}
return compVal;
}
});
System.out.println(&quot;\nSorted in reversed order of playerKey:&quot;);
playersData.stream().forEach(System.out::println);
}
}

[Update]

You can use Map in the following way:

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&lt;String&gt; {
@Override
public int compare(String s1, String s2) {
int compVal;
int n1 = 0, n2 = 0;
String sn1 = &quot;&quot;, sn2 = &quot;&quot;;
// Pattern to find a sequence of digits
Pattern pattern = Pattern.compile(&quot;\\d+&quot;);
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 &amp;&amp; n1 != 0 &amp;&amp; n2 != 0) {
compVal = Integer.compare(n2, n1);
}
return compVal;
}
}
public class Main {
public static void main(String[] args) {
Map&lt;String, HashMap&lt;String, Object&gt;&gt; playersDataMap = new HashMap&lt;&gt;();
for (int i = 1; i &lt;= 10; i++) {
HashMap&lt;String, Object&gt; playerMap = new HashMap&lt;&gt;();
playerMap.put(&quot;name&quot;, &quot;abc&quot; + i);
playerMap.put(&quot;pointsScored&quot;, i * 10);
playersDataMap.put(&quot;x&quot; + i, playerMap);
}
Map&lt;String, HashMap&lt;String, Object&gt;&gt; inversedPlayerDataMap = new TreeMap&lt;&gt;(new MyComparator());
inversedPlayerDataMap.putAll(playersDataMap);
for (Map.Entry&lt;String, HashMap&lt;String, Object&gt;&gt; entry : inversedPlayerDataMap.entrySet()) {
System.out
.println(&quot;playerKey=&quot; + entry.getKey() + &quot;, pointsScored=&quot; + entry.getValue().get(&quot;pointsScored&quot;));
}
}
}

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

答案3

得分: 0

以下是您要翻译的内容:

两个上述答案在一定程度上都是有效的,但它们不能处理混合字符串。

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

以下是我的 invert 函数的代码。

重要提示,我传递的参数 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;
}
英文:

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

Here is the code of my invert function.

Important, the argument i passed as a playersDataMap is a linkedHashMap. For further explanation on LinkedHashMap please go to the following link https://beginnersbook.com/2013/12/linkedhashmap-in-java/. thanks!

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

huangapple
  • 本文由 发表于 2020年5月5日 18:40:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/61611181.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定