排序专家 - SortUtil

JAVA开发排序少不了的,曾几何时以为排序就是数据库SQL order by,后来你会发现,你的数据可能源自于别人的API,也可能直接源自EXCEL…这时要排序,好吧 我去写自定义 Comparator,好累好累的说

我们来看看 排序专家 - SortUtil

主要由下面几个部分组成:

SortUtil

1.排数组.

方法Description
sortArray(T[])对 数组 arrays 进行排序.
sortArray(T[], Comparator<T>…)对 数组 arrays使用 comparator 进行排序.

1.1 sortArray(T[])

对 数组 arrays 进行排序.

示例:

  1. sortArray(toArray(5, 10, 3, 2) = [2,3,5,10]

以前代码需要写成:

  1. public static String toSalesPropertiesIdsJson(Long...itemPropertiesIdLongs){
  2. Arrays.sort(itemPropertiesIdLongs);
  3. return JsonUtil.format(itemPropertiesIdLongs, 0, 0);
  4. }

现在可以重构成:

  1. public static String toSalesPropertiesIdsJson(Long...itemPropertiesIdLongs){
  2. return JsonUtil.format(sortArray(itemPropertiesIdLongs), 0, 0);
  3. }

再如:

  1. // 得到默认分类,目前是最小的
  2. private Long getDefaultCategoryId(Long[] categoriesIds){
  3. Arrays.sort(categoriesIds);
  4. return categoriesIds[0];
  5. }

可以重构成:

  1. // 得到默认分类,目前是最小的
  2. private Long getDefaultCategoryId(Long[] categoriesIds){
  3. return sortArray(categoriesIds)[0];
  4. }

1.2 sortArray(T[], Comparator<T>…)

对 数组 arrays 使用 comparator 进行排序.

示例:场景: 对字符串数组先按照长度比较,如果长度相等,那么再按照字母比较

  1. String[] arrays = { "almn", "fba", "cba" };
  2. Comparator<String> comparator = new Comparator<String>(){
  3. @Override
  4. public int compare(String s1,String s2){
  5. Integer length = s1.length();
  6. Integer length2 = s2.length();
  7. //先判断长度,长度比较
  8. int compareTo = length.compareTo(length2);
  9. //如果长度相等,那么比较自己本身的顺序
  10. if (0 == compareTo){
  11. compareTo = s1.compareTo(s2);
  12. }
  13. return compareTo;
  14. }
  15. };
  16. sortArray(arrays, comparator);
  17. assertArrayEquals(toArray("cba", "fba", "almn"), arrays);

2.排集合

方法Description
sortList(List<T>)对 集合 list 进行排序.
sortList(List<O>, Comparator<O>…)对集合 list,使用指定的 comparators 进行排序.
sortListByFixedOrderPropertyValueArray(List<O>, String, V…)对 集合 list,属性 propertyName 按照固定顺序值 propertyValues 进行排序.
sortListByFixedOrderPropertyValueList(List<O>, String, List<V>)对 集合 list,属性 propertyName 按照固定顺序值 propertyValues 进行排序.
sortListByPropertyNamesValue(List<O>, String…)对集合 list,按照指定属性的值(组合)进行排序.

2.1 sortList(List<T>)

对 集合 list 进行排序.

说明:

  • Collections.sort 底层就是调用的是 Arrays.sort
  • 示例:
  1. sortList(toList(5, 10, 3, 2)) = [2,3,5,10]

2.2 sortList(List<O>, Comparator<O>…)

对集合 list,使用指定的 comparators 进行排序.

示例:场景: 将 user list 按照 id进行排序

  1. List<User> list = new ArrayList<>();
  2. list.add(new User(12L, 18));
  3. list.add(new User(2L, 36));
  4. list.add(new User(5L, 22));
  5. list.add(new User(1L, 8));
  6. SortUtil.sortList(list, new PropertyComparator<User>("id"));
  7. LOGGER.debug(JsonUtil.format(list));

返回:

  1. [
  2. {"id": 1,"age": 8},
  3. {"id": 2,"age": 36},
  4. {"id": 5,"age": 22},
  5. {"id": 12,"age": 18}
  6. ]

当然对于上述示例,你可以直接调用:

  1. SortUtil.sortListByPropertyNamesValue(list, "id");

我们再来个复杂点的例子: 将 user list 按照 "刘备" 排在 "关羽" 前面 进行排序,如果名字相同再按照 age进行排序

  1. User guanyu = new User("关羽", 30);
  2. User liubei60 = new User("刘备", 60);
  3. User liubei25 = new User("刘备", 25);
  4. User liubei30 = new User("刘备", 30);
  5. User liubei10 = new User("刘备", 10);
  6. String[] names = { "刘备", "关羽" };
  7. List<User> list = CollectionsUtil.select(toList(liubei60, liubei30, liubei10, guanyu, liubei25), "name", names);
  8. sortList(
  9. list, //
  10. new PropertyComparator<User>("name", new FixedOrderComparator<>(names)),
  11. new PropertyComparator<User>("age"));

返回:

  1. assertThat(list, contains(liubei10, liubei25, liubei30, liubei60, guanyu));

2.3 sortListByFixedOrderPropertyValueArray(List<O>, String, V…)

对 集合 list,属性 propertyName 按照固定顺序值 propertyValues 进行排序.

示例:场景: 将user list中 "刘备" 排在 "关羽"前面

  1. User zhangfei = new User("张飞", 23);
  2. User guanyu = new User("关羽", 30);
  3. User liubei = new User("刘备", 25);
  4. List<User> list = toList(zhangfei, guanyu, liubei);
  5. List<User> resultList = CollectionsUtil.select(list, "name", "刘备", "关羽");
  6. Collections.sort(resultList, new PropertyComparator<User>("name", new FixedOrderComparator<>("刘备", "关羽")));

此时你可以直接调用:

  1. List<User> resultList = CollectionsUtil.select(list, "name", "刘备", "关羽");
  2. SortUtil.sortListByFixedOrderPropertyValueArray(resultList, "name", "刘备", "关羽"));

返回:

  1. assertThat(resultList, contains(liubei, guanyu));

2.4 sortListByFixedOrderPropertyValueList(List<O>, String, List<V>)

对 集合 list,属性 propertyName 按照固定顺序值 propertyValues 进行排序.

示例:场景: 将user list中 "刘备" 排在 "关羽"前面

  1. User zhangfei = new User("张飞", 23);
  2. User guanyu = new User("关羽", 30);
  3. User liubei = new User("刘备", 25);
  4. List<User> list = toList(zhangfei, guanyu, liubei);
  5. List<User> returnList = CollectionsUtil.select(list, "name", toList("刘备", "关羽"));
  6. returnList = sortListByFixedOrderPropertyValueList(returnList, "name", toList("刘备", "关羽"));

返回:

  1. assertThat(returnList, contains(liubei, guanyu));

2.5 sortListByPropertyNamesValue(List<O>, String…)

对集合 list,按照指定属性的值(组合)进行排序.

示例:场景: 将user list 先按照 id 再按照 age 进行排序

  1. List<User> list = new ArrayList<>();
  2. list.add(new User(12L, 18));
  3. list.add(new User(2L, 36));
  4. list.add(new User(2L, 2));
  5. list.add(new User(2L, 30));
  6. list.add(new User(1L, 8));
  7. SortUtil.sortListByPropertyNamesValue(list, "id", "age");
  8. LOGGER.debug(JsonUtil.formatWithIncludes(list, "id", "age"));

返回:

  1. [
  2. {"id": 1,"age": 8},
  3. {"id": 2,"age": 2},
  4. {"id": 2,"age": 30},
  5. {"id": 2,"age": 36},
  6. {"id": 12,"age": 18}
  7. ]

3.排Map

方法Description
sortMapByKeyAsc(Map<K, V>)按照key asc顺序排序.
sortMapByKeyDesc(Map<K, V>)按照key desc 倒序排序.
sortMapByValueAsc(Map<K, V>)根据value 来顺序排序(asc).
sortMapByValueDesc(Map<K, V>)根据value 来倒序排序(desc).
sortMap(Map<K, V>, Comparator<Entry<K, V>>)使用 基于 Entry 的 mapEntryComparator 来对 map进行排序.

3.1 sortMapByKeyAsc(Map<K, V>)

按照key asc顺序排序.

注意:

  • 原 map 的顺序不变
  • 该方法使用了 PropertyComparator,允许 null key,null key排在最前面
  • 如果直接使用 java.util.TreeMap.TreeMap(Map),TreeMap不允许 key是null,如果有key是null,那么将会抛出 NullPointerException示例:
  1. Map<String, Comparable> map = new HashMap<>();
  2. map.put("a", 123);
  3. map.put("c", 345);
  4. map.put(null, 1345);
  5. map.put("b", 8);
  6. LOGGER.debug(JsonUtil.format(SortUtil.sortMapByKeyAsc(map)));

返回:

  1. {
  2. null: 1345,
  3. "a": 123,
  4. "b": 8,
  5. "c": 345
  6. }

3.2 sortMapByKeyDesc(Map<K, V>)

按照key desc 倒序排序.

注意:

  • 原 map 的顺序不变
  • 该方法使用了 PropertyComparator,允许 null key,null key排在最后面示例:
  1. Map<String, Comparable> map = new HashMap<>();
  2. map.put("a", 123);
  3. map.put("c", 345);
  4. map.put(null, 88);
  5. map.put("b", 8);
  6. LOGGER.debug(JsonUtil.format(SortUtil.sortMapByKeyDesc(map)));

返回:

  1. {
  2. "c": 345,
  3. "b": 8,
  4. "a": 123,
  5. null: 88
  6. }

3.3 sortMapByValueAsc(Map<K, V>)

根据value 来顺序排序(asc).

注意:

  • 原 map 的顺序不变示例:
  1. Map<String, Comparable> map = new HashMap<>();
  2. map.put("a", 123);
  3. map.put("c", 345);
  4. map.put("b", 8);
  5. LOGGER.debug(JsonUtil.format(SortUtil.sortMapByValueAsc(map)));

返回:

  1. {
  2. "b": 8,
  3. "a": 123,
  4. "c": 345
  5. }

3.4 sortMapByValueDesc(Map<K, V>)

根据value 来倒序排序(desc).

注意:

  • 原 map 的顺序不变示例:
  1. Map<String, Comparable> map = new LinkedHashMap<>();
  2. map.put("a", 123);
  3. map.put("c", 345);
  4. map.put("b", 8);
  5. LOGGER.debug(JsonUtil.format(SortUtil.sortMapByValueDesc(map)));

返回:

  1. {
  2. "c": 345,
  3. "a": 123,
  4. "b": 8
  5. }

3.5 sortMap(Map<K, V>, Comparator<Entry<K, V>>)

使用 基于 Entry 的 mapEntryComparator 来对 map进行排序.

说明:

  • 原 map 的顺序不变
  • 由于是对Entry排序的, 既可以按照key来排序,也可以按照value来排序哦示例:比如有以下的map
  1. Map<String, Integer> map = new HashMap<>();
  2. map.put("a13", 123);
  3. map.put("a2", 345);
  4. map.put("a8", 8);

如果我们只是使用 :

  1. LOGGER.debug(JsonUtil.format(SortUtil.sortByKeyAsc(map)));

返回:

  1. {
  2. "a13": 123,
  3. "a2": 345,
  4. "a8": 8
  5. }

此时可以看出 a13是以字符串的形式进行比较的,我们可以使用以下的自定义的 Comparator,来达到排序的效果

  1. PropertyComparator<Entry<String, Integer>> propertyComparator = new PropertyComparator<Map.Entry<String, Integer>>(
  2. "key",
  3. new RegexGroupNumberComparator("a(\\d*)"));
  4. LOGGER.debug(JsonUtil.format(SortUtil.sortMap(map, propertyComparator)));

返回:

  1. {
  2. "a2": 345,
  3. "a8": 8,
  4. "a13": 123
  5. }