List中部分数据按map的排序值排序

场景

最近项目上遇到一个需求:运营后台设置商品分子分类组合查询条件,前端APP由子分类进入展示商品列表。
其中有一种查询条件是在后台添加或导入商品,商品可指定展示的排序,排序号可以重复,也可不设置排序。
商品需满足特定条件才展示,如定位的门店有库存且上架,即可能后台设置了10个商品,但只有5个商品满足展示条件,也可能都不满足条件都不展示。
满足上架条件通过ES查询DSL来过滤,后台配置的打分规则用于ES排序,后台设置的商品排序在接口里由Java代码来实现。
前端APP展示满足条件可展示的商品列表,如果设置了排序号按从小到大排序,如果排序号重复按后台列表展示的顺序展示,如果没有设置排序按ES查询里的打分排序。

如后台设置了如下商品:
商品1008,无排序
商品1001,排序1
商品1002,排序6
商品1003,排序5
商品1004,排序3
商品1005,排序3
商品1006,排序4
商品1007,排序2
商品1009,无排序

只有商品1002,1003,1004,1005,1007满足展示条件,那么展示的列表应为:
商品1007,排序2
商品1004,排序3
商品1005,排序3
商品1003,排序5
商品1002,排序6
商品1008,无排序
商品1009,无排序
注:因商品1004,1005排序值相同都为3,按后台展示的顺序展示,1004排前面;商品1008,1009没有设置排序,排在列表的最后面。

实际项目中运营后台设置按商品编码的组合条件为json格式,如:{"productCodes":"1001-1,1002,1003-2"},
通过构建ES查询条件查询ES,在由Java代码里按运营后台的设置来排序,最后通过redis查询商品库存、价格等构建商品列表数据。
这里我们主要讨论Java的排序,因此忽略ES查询和构建商品数据,将需求描述简化后,用代码模拟如下:

// 运营后台已添加且满足可展示条件的商品编码列表,注:1008,1009后台添加了商品但为设置排序号
List<String> productCodes = new ArrayList<>();
productCodes.add("1008");
productCodes.add("1002");
productCodes.add("1003");
productCodes.add("1004");
productCodes.add("1005");
productCodes.add("1007");
productCodes.add("1009");

// 运营后台设置的商品排序map,key:商品编码,value:排序号
Map<String, Integer> productSortMap = new LinkedHashMap<>();
productSortMap.put("1001", 1);
productSortMap.put("1002", 6);
productSortMap.put("1003", 5);
productSortMap.put("1004", 3);
productSortMap.put("1005", 3);
productSortMap.put("1006", 4);
productSortMap.put("1007", 2);

思路

  1. 遍历productCodes列表,如果设置了排序值在列表中去掉,并且构建一个map保存
  2. 通过该map将不满足可展示条件的商品编码在运营后台设置的商品排序map中去掉
  3. 运营后台设置的商品排序map按value排序,加到productCodes列表的最前面

实现

// 遍历productCodes列表,将设置了排序值的商品构建一个map保存,并在列表中去掉该商品
Map<String, Integer> canDisplayProductSortMap = null;
Iterator<String> iterator = productCodes.iterator();
while (iterator.hasNext()) {
    String productCode = iterator.next();

    // 在运营后台没有设置排序的跳过处理
    if (!productSortMap.containsKey(productCode)) {
        continue;
    }

    // 懒汉模式创建map,当都没设置排序时不用创建map
    if (canDisplayProductSortMap == null) {
        canDisplayProductSortMap = new LinkedHashMap<>();
    }

    canDisplayProductSortMap.put(productCode, productSortMap.get(productCode));
    // 将设置了排序的商品编码在列表里去掉
    iterator.remove();
}

if (canDisplayProductSortMap != null) {
    Map<String, Integer> finalCanDisplayProductSortMap = canDisplayProductSortMap;
    // 通过该map将不满足可展示条件的商品编码在运营后台设置的商品排序map中去掉
    productSortMap.entrySet().removeIf(entry -> !finalCanDisplayProductSortMap.containsKey(entry.getKey()));
    // 运营后台设置的商品排序map按value排序,加到productCodes列表的最前面
    productCodes.addAll(0, productSortMap.entrySet().stream().sorted(Map.Entry.comparingByValue()).map(Map.Entry::getKey).collect(Collectors.toList()));
    // 打印最终排序好的商品编码列表,输出为:[1007, 1004, 1005, 1003, 1002, 1008, 1009]
    System.out.println(productCodes);
} else {
    // 如果可展示的商品在后台都没有设置排序,则无需处理
    System.out.println(productCodes);
}

总结

  • list可通过list.iterator()遍历支持在遍历中删除数据
  • map可通过map.entrySet().stream().sorted(Map.Entry.comparingByValue())按value值排序

参考

原文地址:https://www.cnblogs.com/cdfive2018/p/14803323.html