有一个 Map,其键类型为
String
作为对象列表表示的值,如下所示:
Map<String, List<ScoreAverage>> averagesMap
ScoreAverage
记录:
public record ScoreAverage(
@JsonProperty("average") double average,
@JsonProperty("name") String name
) {}
map保存数据如下:
{
"averagesMap":{
"A":[
{
"average":4.0,
"name":"Accounting"
},
{
"average":4.0,
"name":"company-wide"
},
{
"average":4.0,
"name":"Engineering"
}
],
"B":[
{
"average":3.0,
"name":"Engineering"
},
{
"average":3.0,
"name":"company-wide"
},
{
"average":3.0,
"name":"Accounting"
}
],
"C":[
{
"average":2.0,
"name":"company-wide"
},
{
"average":2.0,
"name":"Engineering"
},
{
"average":2.0,
"en":"Accounting"
}
],
"specialAverages":[
{
"average":2.5,
"name":"Engineering"
},
{
"average":2.5,
"name":"company-wide"
},
{
"average":2.5,
"name":"Accounting"
}
]
}
}
我想要实现的是使用
name
属性按照运行时指定的顺序对地图中的每个对象列表进行动态排序,例如:
1st item of list -> company-wide
2nd item of list -> Engineering
3rd item of list -> Accounting
最简单的方法是什么?
为此,首先您需要建立所需的顺序。这样它将被封装在一个变量中,并在运行时作为参数传递给负责排序的方法。这样,排序顺序将是动态的,取决于提供的参数。
在下面的代码中,
List
被用于该目的。排序是根据每个name
在sortingRule
列表中占据的索引。
下一步是在它的基础上创建
Comparator
。当sortingRule.contains(score.name())
没有出现在name
中时,我正在使用条件sortingRule
作为预防措施,例如打字错误等。这样,所有这些对象将被放置在排序列表的末尾。
Comparator<ScoreAverage> dynamicComparator =
Comparator.comparingInt(score -> sortingRule.contains(score.name()) ?
sortingRule.indexOf(score.name()) :
sortingRule.size());
如果我们放弃条件比较器归结为
Comparator.comparingInt(score -> sortingRule.indexOf(score.name()));
这样,所有未识别的对象(如果有的话)将被分组在排序列表的开头。
最后,我们需要用这个比较器对映射中的每个值进行排序。
迭代实现(注意:每个列表的防御副本都是为了保持源完好无损)。
public static Map<String, List<ScoreAverage>> sortByRule(Map<String, List<ScoreAverage>> averagesMap,
List<String> sortingRule) {
Comparator<ScoreAverage> dynamicComparator =
Comparator.comparingInt(score -> sortingRule.contains(score.name()) ?
sortingRule.indexOf(score.name()) :
sortingRule.size());
Map<String, List<ScoreAverage>> result = new HashMap<>();
for (Map.Entry<String, List<ScoreAverage>> entry: averagesMap.entrySet()) {
List<ScoreAverage> copy = new ArrayList<>(entry.getValue());
copy.sort(dynamicComparator);
result.put(entry.getKey(), copy);
}
return result;
}
基于流的实现(注意:源映射中的列表不会被修改,每个条目将被一个新条目替换)。
public static Map<String, List<ScoreAverage>> sortByRule(Map<String, List<ScoreAverage>> averagesMap,
List<String> sortingRule) {
Comparator<ScoreAverage> dynamicComparator =
Comparator.comparingInt(score -> sortingRule.contains(score.name()) ?
sortingRule.indexOf(score.name()) :
sortingRule.size());
return averagesMap.entrySet().stream()
.map(entry -> Map.entry(entry.getKey(),
entry.getValue().stream()
.sorted(dynamicComparator)
.collect(Collectors.toList())))
.collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue));
}
主要()
public static void main(String[] args) {
Map<String, List<ScoreAverage>> averagesMap =
Map.of("A", List.of(new ScoreAverage(4.0, "Accounting"),
new ScoreAverage(4.0, "company-wide"),
new ScoreAverage(4.0, "Engineering")),
"B", List.of(new ScoreAverage(3.0, "Engineering"),
new ScoreAverage(3.0, "company-wide"),
new ScoreAverage(3.0, "Accounting")),
"C", List.of(new ScoreAverage(2.0, "company-wide"),
new ScoreAverage(2.0, "Engineering"),
new ScoreAverage(2.0, "Accounting")),
"specialAverages", List.of(new ScoreAverage(2.5, "Engineering"),
new ScoreAverage(2.5, "company-wide"),
new ScoreAverage(2.5, "Accounting")));
List<String> sortingRule = List.of("company-wide", "Engineering", "Accounting");
sortByRule(averagesMap, sortingRule).forEach((k, v) -> System.out.println(k + " : " + v));
}
输出
A : [ScoreAverage[average=4.0, name=company-wide], ScoreAverage[average=4.0, name=Engineering], ScoreAverage[average=4.0, name=Accounting]]
B : [ScoreAverage[average=3.0, name=company-wide], ScoreAverage[average=3.0, name=Engineering], ScoreAverage[average=3.0, name=Accounting]]
C : [ScoreAverage[average=2.0, name=company-wide], ScoreAverage[average=2.0, name=Engineering], ScoreAverage[average=2.0, name=Accounting]]
specialAverages : [ScoreAverage[average=2.5, name=company-wide], ScoreAverage[average=2.5, name=Engineering], ScoreAverage[average=2.5, name=Accounting]]
更新
也可以结合封装在列表中的排序规则和负责对
排序规则中不存在的元素进行排序的
Comparator
。 排序规则 和比较器都将在运行时动态提供。
为此,必须更改方法签名(需要添加第三个参数):
public static Map<String, List<ScoreAverage>> sortByRule(Map<String, List<ScoreAverage>> averagesMap,
List<String> sortingRule,
Comparator<ScoreAverage> downstreamComparator)
比较器看起来像这样:
Comparator<ScoreAverage> dynamicComparator =
Comparator.<ScoreAverage>comparingInt(score -> sortingRule.contains(score.name()) ?
sortingRule.indexOf(score.name()) :
sortingRule.size())
.thenComparing(downstreamComparator);
它将所有名称为contained的对象分组在结果列表开头的
sortingRule
中,其余部分将按照downstreamComparator
排序。
main 中的方法调用如下所示:
sortByRule(averagesMap, sortingRule, Comparator.comparing(ScoreAverage::name))
.forEach((k, v) -> System.out.println(k + " : " + v));
如果您应用这些更改并提供仅包含一个字符串
sortingRule
的"company-wide"
,您将获得此output:
A : [ScoreAverage[average=4.0, name=company-wide], ScoreAverage[average=4.0, name=Accounting], ScoreAverage[average=4.0, name=Engineering]]
B : [ScoreAverage[average=3.0, name=company-wide], ScoreAverage[average=3.0, name=Accounting], ScoreAverage[average=3.0, name=Engineering]]
C : [ScoreAverage[average=2.0, name=company-wide], ScoreAverage[average=2.0, name=Accounting], ScoreAverage[average=2.0, name=Engineering]]
specialAverages : [ScoreAverage[average=2.5, name=company-wide], ScoreAverage[average=2.5, name=Accounting], ScoreAverage[average=2.5, name=Engineering]]