如何在Java中扁平化和排序具有ArrayList值的HashMap?

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

How to flatten and sort a HashMap with ArrayList values in Java?

问题

所以,我有一个哈希映射,其中键为字符串,值为ArrayList。

static HashMap<String, ArrayList> scores = new HashMap<>();


然后我只是使用Scanner类请求输入:

Scanner sc = new Scanner(System.in);
String input = sc.nextLine();

String[] inputArr = input.split(" ");


然后,如果玩家存在,我只需将分数添加给他,如果不存在,它会创建一个新条目:

for (int i = 0; i < inputArr.length; i += 2) {

String UID = inputArr[i];
int score = Integer.parseInt(inputArr[i + 1]);

if (!scores.containsKey(UID)) {
    ArrayList<Integer> list = new ArrayList<>();
    list.add(score);
    scores.put(UID, list);
} else {
    scores.get(UID).add(score);
}

}


所以,例如,如果我在控制台中输入`1 100 2 200 3 300 1 200`,
我会得到`{1=[100, 200], 2=[200], 3=[300]}`

现在我需要这个哈希映射被“打开”,看起来像这样:`3 300 1 200 2 200 1 100`。
请注意,输出按**值**降序排序。

我还尝试过不同的方法,如SortedTreeMap或TreeBag,但似乎都不起作用。
英文:

So, I have a hashmap which has a String as key, and an Arraylist as Value.

static HashMap&lt;String, ArrayList&lt;Integer&gt;&gt; scores = new HashMap&lt;&gt;();

Then I just request Input with the Scanner Class:

Scanner sc = new Scanner(System.in);
String input = sc.nextLine();

String[] inputArr = input.split(&quot; &quot;);

And then I just add the score to the player if he exists, and if he doesn't it just creates a new entry

for (int i = 0; i &lt; inputArr.length; i += 2) {

    String UID = inputArr[i];
    int score = Integer.parseInt(inputArr[i + 1]);

    if (!scores.containsKey(UID)) {
        ArrayList&lt;Integer&gt; list = new ArrayList&lt;&gt;();
        list.add(score);
        scores.put(UID, list);
    } else {
        scores.get(UID).add(score);
    }

}

So for example, if I Input 1 100 2 200 3 300 1 200 into the console,
I receive {1=[100, 200], 2=[200], 3=[300]}

Now what I need is this Hashmap to be "opened up" and look like this: 3 300 1 200 2 200 1 100.
Note that the Output is sorted descending by value.

I also tried different methods, like a SortedTreeMap or a TreeBag, but none of them seem to work

答案1

得分: 2

你可以在地图的条目上执行flatMap操作,将每个String条目转换为List&lt;Integer&gt;,形成多个StringInteger的条目流。然后,你可以使用你喜欢的比较器对条目进行排序。

var result = scores.entrySet().stream()
    .flatMap(
        entry -&gt; entry.getValue().stream().map(v -&gt; Map.entry(entry.getKey(), v))
    )
    .sorted(
        Map.Entry.&lt;String, Integer&gt;comparingByValue().reversed()
            // if you would like to also break ties on the values by comparing the keys
            //.thenComparing(Map.Entry.comparingByKey())
    )
    .toList();

result是一个List&lt;Entry&lt;String, Integer&gt;&gt;。打印result会得到:

[3=300, 1=200, 2=200, 1=100]

另外,请注意,将用户输入添加到地图的if语句可以简化为以下使用computeIfAbsent的形式:

scores.computeIfAbsent(UID, x -&gt; new ArrayList&lt;&gt;()).add(score);

(注意:这是你的代码的翻译,不包括代码部分。)

英文:

You could do a flatMap on the map's entries, transforming each entry of String to List&lt;Integer&gt;, into a stream of multiple entries of String to Integer. Then you can just sort the entries with a comparator you prefer.

var result = scores.entrySet().stream()
    .flatMap(
        entry -&gt; entry.getValue().stream().map(v -&gt; Map.entry(entry.getKey(), v))
    )
    .sorted(
        Map.Entry.&lt;String, Integer&gt;comparingByValue().reversed()
            // if you would like to also break ties on the values by comparing the keys
            //.thenComparing(Map.Entry.comparingByKey())
    )
    .toList();

result is a List&lt;Entry&lt;String, Integer&gt;&gt;. Printing result gives you

[3=300, 1=200, 2=200, 1=100]

Also note that your if statement for adding the user input into the map can be simplified to the following using computeIfAbsent:

scores.computeIfAbsent(UID, x -&gt; new ArrayList&lt;&gt;()).add(score);

huangapple
  • 本文由 发表于 2023年3月7日 17:47:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75660305.html
匿名

发表评论

匿名网友

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

确定