java - 我们如何按值降序对 Map 进行排序,然后按键按字母顺序排序?
问题描述
我目前正在做以下编程任务:Prize Draw,语句为:
为了参加抽奖,每个人都给出了他/她的名字。
名字的每个字母都有一个值,即它在英文字母表中的排名。A 和 a 的等级为 1,B 和 b 的等级为 2,依此类推。
名字的长度被添加到这些等级的总和中,因此是一个数字 som。
一组随机权重与名字相关联,每个 som 乘以其相应的权重,得到他们所谓的中奖号码。
例子:
名称:“COLIN,AMANDBA,AMANDAB,CAROL,PauL,JOSEPH” 权重:[1, 4, 4, 5, 2, 1]
PauL -> som = 名字长度 + 16 + 1 + 21 + 12 = 4 + 50 -> 54与 PauL 相关的权重为 2,因此 PauL 的中奖号码为 54 * 2 = 108。
现在可以按中奖号码的降序对名字进行排序。当两个人的中奖号码相同时,按名字的字母顺序排列。任务:
parameters: st a string of firstnames, we an array of weights, n a rank return: the firstname of the participant whose rank is n (ranks are numbered from 1)
例子:
名称:“COLIN,AMANDBA,AMANDAB,CAROL,PauL,JOSEPH” 权重:[1, 4, 4, 5, 2, 1] n: 4
该函数应返回:“PauL”
笔记:
If st is empty return "No participants". If n is greater than the number of participants then return "Not enough participants".
我认为伪代码为:
if names are empty return No participants
if n is greater than names length return Not enough participants
for each name
sum its length
for each character
sum its value in the alphabet
multiply sum by weight
store name and sum in the map
sort map descending by value
sort map alphabetically by key (if values are equal)
return key n from the map
此外,我还编写了以下代码:
import java.util.*;
import java.util.stream.*;
class Rank {
public static String nthRank(String st, Integer[] we, int n) {
System.out.println("\n\n\nNames: "+st+" weights: "+Arrays.toString(we)+" n: "+n);
if(st.isEmpty()) return "No participants";
String[] names = st.split(",");
if(n > names.length) return "Not enough participants";
String alphabet = "abcdefghijklmnopqrstuvwxyz";
int sum = 0;
Map<String, Integer> map = new HashMap<String, Integer>();
for(int i = 0; i < names.length; i++){
String currentName = names[i];
sum += currentName.length();
for(int j = 0; j < currentName.length(); j++){
char currentChar = Character.toLowerCase(currentName.charAt(j));
sum += alphabet.indexOf(currentChar) + 1;
}
map.put(currentName, sum*we[i]);
System.out.println("Map: "+map.toString());
sum = 0;
}
map = map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
System.out.println("\n\nSorted Map: "+map.toString());
Object[] namesByWinningNumber = map.keySet().toArray();
Arrays.sort(namesByWinningNumber);
System.out.println("\n\n\nSorted names array: "+ Arrays.toString(namesByWinningNumber));
return map.keySet().toArray()[n-1].toString();
}
}
当输入为:
Names: William,Willaim,Olivia,Olivai,Lily,Lyli weights: [1, 1, 1, 1, 1, 1] n: 1
预期是:
Willaim
但代码输出:
William
作为痕迹:
Names: William,Willaim,Olivia,Olivai,Lily,Lyli weights: [1, 1, 1, 1, 1, 1] n: 1
Map: {William=86}
Map: {William=86, Willaim=86}
Map: {Olivia=74, William=86, Willaim=86}
Map: {Olivia=74, Olivai=74, William=86, Willaim=86}
Map: {Olivia=74, Olivai=74, William=86, Willaim=86, Lily=62}
Map: {Olivia=74, Olivai=74, William=86, Willaim=86, Lily=62, Lyli=62}
Sorted Map: {William=86, Willaim=86, Olivia=74, Olivai=74, Lily=62, Lyli=62}
Sorted names array: [Lily, Lyli, Olivai, Olivia, Willaim, William]
因此,如我们所见,首先我按值按降序对地图进行排序。然后我想如果我得到键并按字母顺序对它们进行排序,它只会处理具有完全相同值的键;但是,一切都解决了。
我们如何才能按值降序对 Map 进行排序,然后按键按字母顺序排序‽‽‽</p>
我也读过:
- 按值对 Map<Key, Value> 进行排序
- 打印 Java 数组的最简单方法是什么?
- 在Java中对数组进行排序
- 为什么 java.util.Set 没有 get(int index)?
- 很好地打印 Java 集合(toString 不返回漂亮的输出)
- 将 LinkedHashMap 中的所有键提取到列表中的方法
- 如何根据索引而不是键从 LinkedHashMap 获取值?
- 按值对 Map<Key, Value> 进行排序
- 如何有效地迭代 Java Map 中的每个条目?
编辑:
我读到:如何为 Map.Entry 中的 Map 值编写 java 8 Comparator
我也尝试编写自己的比较器:
Comparator<Map.Entry> outerComparator = (pair1, pair2) -> {
if ((int)pair1.getValue() > (int)pair2.getValue()){
return 1;
}else if ((int)pair1.getValue() < (int)pair2.getValue()){
return -1;
}else{
return pair1.getKey().toString().compareTo(pair2.getKey().toString());
}
};
并按如下方式使用它:
map = map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(outerComparator))
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
但是,我们的控制台说:
./src/main/java/Rank.java:40: error: incompatible types: inference variable V has incompatible bounds
.sorted(Map.Entry.comparingByValue(outerComparator))
^
equality constraints: Integer
lower bounds: Entry,Object
where V,K are type-variables:
V extends Object declared in method <K,V>comparingByValue(Comparator<? super V>)
K extends Object declared in method <K,V>comparingByValue(Comparator<? super V>)
./src/main/java/Rank.java:41: error: incompatible types: cannot infer type-variable(s) T,K#1,U,M,K#2,V#1
.collect(Collectors.toMap(
^
(argument mismatch; invalid method reference
method getKey in interface Entry<K#3,V#2> cannot be applied to given types
required: no arguments
found: Object
reason: actual and formal argument lists differ in length)
where T,K#1,U,M,K#2,V#1,K#3,V#2 are type-variables:
T extends Object declared in method <T,K#1,U,M>toMap(Function<? super T,? extends K#1>,Function<? super T,? extends U>,BinaryOperator<U>,Supplier<M>)
K#1 extends Object declared in method <T,K#1,U,M>toMap(Function<? super T,? extends K#1>,Function<? super T,? extends U>,BinaryOperator<U>,Supplier<M>)
U extends Object declared in method <T,K#1,U,M>toMap(Function<? super T,? extends K#1>,Function<? super T,? extends U>,BinaryOperator<U>,Supplier<M>)
M extends Map<K#1,U> declared in method <T,K#1,U,M>toMap(Function<? super T,? extends K#1>,Function<? super T,? extends U>,BinaryOperator<U>,Supplier<M>)
K#2 extends Object declared in class LinkedHashMap
V#1 extends Object declared in class LinkedHashMap
K#3 extends Object declared in interface Entry
V#2 extends Object declared in interface Entry
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
2 errors
在此之前是完整的代码:
import java.util.*;
import java.util.stream.*;
class Rank {
public static String nthRank(String st, Integer[] we, int n) {
System.out.println("\n\n\nNames: "+st+" weights: "+Arrays.toString(we)+" n: "+n);
if(st.isEmpty()) return "No participants";
String[] names = st.split(",");
if(n > names.length) return "Not enough participants";
String alphabet = "abcdefghijklmnopqrstuvwxyz";
int sum = 0;
Map<String, Integer> map = new HashMap<String, Integer>();
for(int i = 0; i < names.length; i++){
String currentName = names[i];
sum += currentName.length();
for(int j = 0; j < currentName.length(); j++){
char currentChar = Character.toLowerCase(currentName.charAt(j));
sum += alphabet.indexOf(currentChar) + 1;
}
map.put(currentName, sum*we[i]);
System.out.println("Map: "+map.toString());
sum = 0;
}
Comparator<Map.Entry> outerComparator = (pair1, pair2) -> {
if ((int)pair1.getValue() > (int)pair2.getValue()){
return 1;
}else if ((int)pair1.getValue() < (int)pair2.getValue()){
return -1;
}else{
return pair1.getKey().toString().compareTo(pair2.getKey().toString());
}
};
map = map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(outerComparator))
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
System.out.println("\n\nSorted Map: "+map.toString());
return map.keySet().toArray()[n-1].toString();
}
}
作为一个新的尝试,我把它写成一个单独的类:
class MapComparator implements Comparator<Map.Entry> {
@Override
public int compare(Map.Entry pair1, Map.Entry pair2) {
int valueCompare = - ( pair1.getValue().compareTo(pair2.getValue()) );
int nameCompare = pair1.getKey().compareTo(pair2.getKey());
if (valueCompare == 0) {
return ((nameCompare == 0) ? valueCompare : nameCompare);
} else {
return valueCompare;
}
}
}
我认为它可以很好地用作:
map = map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(MapComparator.compare()))
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
然后我们的控制台声称:
./src/main/java/Rank.java:40: error: method compare in class Rank.MapComparator cannot be applied to given types;
.sorted(Map.Entry.comparingByValue(MapComparator.compare()))
^
required: Entry,Entry
found: no arguments
reason: actual and formal argument lists differ in length
./src/main/java/Rank.java:41: error: incompatible types: cannot infer type-variable(s) T,K#1,U,M,K#2,V#1
.collect(Collectors.toMap(
^
(argument mismatch; invalid method reference
method getKey in interface Entry<K#3,V#2> cannot be applied to given types
required: no arguments
found: Object
reason: actual and formal argument lists differ in length)
where T,K#1,U,M,K#2,V#1,K#3,V#2 are type-variables:
T extends Object declared in method <T,K#1,U,M>toMap(Function<? super T,? extends K#1>,Function<? super T,? extends U>,BinaryOperator<U>,Supplier<M>)
K#1 extends Object declared in method <T,K#1,U,M>toMap(Function<? super T,? extends K#1>,Function<? super T,? extends U>,BinaryOperator<U>,Supplier<M>)
U extends Object declared in method <T,K#1,U,M>toMap(Function<? super T,? extends K#1>,Function<? super T,? extends U>,BinaryOperator<U>,Supplier<M>)
M extends Map<K#1,U> declared in method <T,K#1,U,M>toMap(Function<? super T,? extends K#1>,Function<? super T,? extends U>,BinaryOperator<U>,Supplier<M>)
K#2 extends Object declared in class LinkedHashMap
V#1 extends Object declared in class LinkedHashMap
K#3 extends Object declared in interface Entry
V#2 extends Object declared in interface Entry
./src/main/java/Rank.java:54: error: cannot find symbol
int valueCompare = - ( pair1.getValue().compareTo(pair2.getValue()) );
^
symbol: method compareTo(Object)
location: class Object
./src/main/java/Rank.java:55: error: cannot find symbol
int nameCompare = pair1.getKey().compareTo(pair2.getKey());
^
symbol: method compareTo(Object)
location: class Object
4 errors
总结一下,目前完整的代码是:
import java.util.*;
import java.util.stream.*;
class Rank {
public static String nthRank(String st, Integer[] we, int n) {
System.out.println("\n\n\nNames: "+st+" weights: "+Arrays.toString(we)+" n: "+n);
if(st.isEmpty()) return "No participants";
String[] names = st.split(",");
if(n > names.length) return "Not enough participants";
String alphabet = "abcdefghijklmnopqrstuvwxyz";
int sum = 0;
Map<String, Integer> map = new HashMap<String, Integer>();
for(int i = 0; i < names.length; i++){
String currentName = names[i];
sum += currentName.length();
for(int j = 0; j < currentName.length(); j++){
char currentChar = Character.toLowerCase(currentName.charAt(j));
sum += alphabet.indexOf(currentChar) + 1;
}
map.put(currentName, sum*we[i]);
System.out.println("Map: "+map.toString());
sum = 0;
}
Comparator<Map.Entry> outerComparator = (pair1, pair2) -> {
if ((int)pair1.getValue() > (int)pair2.getValue()){
return 1;
}else if ((int)pair1.getValue() < (int)pair2.getValue()){
return -1;
}else{
return pair1.getKey().toString().compareTo(pair2.getKey().toString());
}
};
map = map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(MapComparator.compare()))
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
System.out.println("\n\nSorted Map: "+map.toString());
return map.keySet().toArray()[n-1].toString();
}
class MapComparator implements Comparator<Map.Entry> {
@Override
public int compare(Map.Entry pair1, Map.Entry pair2) {
int valueCompare = - ( pair1.getValue().compareTo(pair2.getValue()) );
int nameCompare = pair1.getKey().compareTo(pair2.getKey());
if (valueCompare == 0) {
return ((nameCompare == 0) ? valueCompare : nameCompare);
} else {
return valueCompare;
}
}
}
}
解决方案
关于错误:
./src/main/java/Rank.java:40: error: method compare in class Rank.MapComparator cannot be applied to given types;
.sorted(Map.Entry.comparingByValue(MapComparator.compare()))
中的compare
方法MapComparator
不是静态的。除了Map.Entry.comparingByValue
in 的方法Map.Entry
需要 a Comparator
,而不是 from 的结果MapComparator.compare()
。
在这里,我认为您打算通过比较地图条目来排序,使用MapComparator
,而不是地图的值(这是comparingByValue
会做的)。所以你要:
map = map.entrySet().stream().sorted(new MapComparator()))
但是您MapComparator
也应该Comparator<Map.Entry<String, Integer>>
因为Map.Entry
.
推荐阅读
- python - 仅在具有多索引的一级系列上使用 agg 方法
- assembly - MIPS 将 $a0 中的字符转换为大写
- python - 为什么我的程序在第二个 for 循环中不起作用?
- firebase - 在firebase控制台中单击文档时,如何防止文档字段在firestore数据库中被消耗?
- c# - 选择标签 ASP.NET Core 没有项目
- sql-server - 使用 EXECUTE 从 SQL Server 调用用户定义函数时的不同标量结果
- c# - 为什么 WPF 定义它自己的类型来表示二维空间中的点而不是使用 System.Numerics.Vector2
- c++ - 深度测试丢弃自定义帧缓冲区上的片段
- android - Kotlin Retrofit Rx android.os.NetworkOnMainThreadException
- python - 过采样后完全忽略了一类