使用 Runetime 提供的属性动态排序列表

问题描述 投票:0回答:1

有一个 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

最简单的方法是什么?

java list sorting hashmap comparator
1个回答
2
投票

为此,首先您需要建立所需的顺序。这样它将被封装在一个变量中,并在运行时作为参数传递给负责排序的方法。这样,排序顺序将是动态的,取决于提供的参数。

在下面的代码中,

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]]
© www.soinside.com 2019 - 2024. All rights reserved.