英文:
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<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.
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" ...
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 < 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.
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. 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<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:
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
答案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<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;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论