在未知值之前对具有已知值的列表进行排序
Sort a list with known values before unknown values
我正在尝试使用以下规则对列表进行排序:
- 已知值应排在未知值之前。
- 已知值应按单独定义的键排序。
- 未知值应按其自然顺序排序。
我有 (1) 和 (2),只是在努力将 (3) 添加到组合中。
到目前为止我有这个:
List<String> values = Arrays.asList(
"red", "orange", "yellow", "green", "blue", "indigo", "violet");
ImmutableMap<String, Integer> map = ImmutableMap.of("red", 1, "green", 2, "blue", 3);
Ordering<String> order = Ordering.natural()
.nullsLast()
.onResultOf(Functions.forMap(map, null));
Collections.sort(values, order);
System.out.println(values);
产生:
[red, green, blue, orange, yellow, indigo, violet]
但最后 4 个是按原始顺序排列的,而我希望它们按自然顺序排序:
[red, green, blue, indigo, orange, violet, yellow]
我唯一能想到的就是编写自己的自定义函数,它在地图中查找内容并将地图结果添加到原始值之前,如果找不到则使用地图大小 - 例如它会 return:
"1-red", "4-orange", "4-yellow", "2-green", "3-blue", "4-indigo", "4-violet"
但这仅在映射值是整数时才有效,并且需要数字格式以在“10”之前排序“02”等。
有人有更好的方法来实现这个目标吗?
这是 Guava 版本(当您使用 Java 7 或更低版本时):
Ordering<String> ordering = Ordering.natural().nullsLast()
.onResultOf(Functions.forMap(map, null))
.compound(Ordering.natural());
这是使用纯 Comparator
的非 Guava 版本(在 JDK 8+ 上):
Comparator<String> comparator = Comparator
.<String, Integer>comparing(map::get, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(Comparator.naturalOrder());
PS。如您所见,Guava API 的类型推断更好(无需指定显式类型参数)。
我认为此解决方案应该可以解决您的问题。对于使用 ArrayList
s,我深表歉意——我在 Java 8 API 中找不到与 ImmutableMap
对应的任何文档。我还假设 natural 顺序表示 ASCII 顺序。希望这会有所帮助:)
//Values to be sorted
ArrayList<Object> values = new ArrayList<>();
values.add("red");
values.add("orange");
values.add("orange");
values.add("yellow");
values.add("green");
values.add("blue");
values.add("indigo");
values.add("violet");
values.add(1); //I added 1 to verify output
//List containing order of known values
ArrayList<Object> knownOrder = new ArrayList<>();
knownOrder.add("red");
knownOrder.add(1);
knownOrder.add("green");
knownOrder.add("blue");
knownOrder.add(3);
ArrayList<Object> knownValues = new ArrayList<>();
ArrayList<Object> unknownValues = new ArrayList<>();
for (Object value: values) {
if (knownOrder.contains(value)) {
knownValues.add(value);
}else {
unknownValues.add(value);
}
}
//Sort known values in required order
Collections.sort(knownValues, (m1, m2)->knownOrder.indexOf(m1)-knownOrder.indexOf(m2));
//Sort unknown values in natural order
Collections.sort(unknownValues, (m1, m2)->m1.toString().charAt(0)-m2.toString().charAt(0));
//Combine the known and unknown values into one ArrayList
knownValues.addAll(unknownValues);
System.out.println(knownValues);
//Prints [red, 1, green, blue, indigo, orange, orange, violet, yellow]
我还应该提到:此解决方案不适用于字符串和原始包装器以外的对象。
我正在尝试使用以下规则对列表进行排序:
- 已知值应排在未知值之前。
- 已知值应按单独定义的键排序。
- 未知值应按其自然顺序排序。
我有 (1) 和 (2),只是在努力将 (3) 添加到组合中。
到目前为止我有这个:
List<String> values = Arrays.asList(
"red", "orange", "yellow", "green", "blue", "indigo", "violet");
ImmutableMap<String, Integer> map = ImmutableMap.of("red", 1, "green", 2, "blue", 3);
Ordering<String> order = Ordering.natural()
.nullsLast()
.onResultOf(Functions.forMap(map, null));
Collections.sort(values, order);
System.out.println(values);
产生:
[red, green, blue, orange, yellow, indigo, violet]
但最后 4 个是按原始顺序排列的,而我希望它们按自然顺序排序:
[red, green, blue, indigo, orange, violet, yellow]
我唯一能想到的就是编写自己的自定义函数,它在地图中查找内容并将地图结果添加到原始值之前,如果找不到则使用地图大小 - 例如它会 return:
"1-red", "4-orange", "4-yellow", "2-green", "3-blue", "4-indigo", "4-violet"
但这仅在映射值是整数时才有效,并且需要数字格式以在“10”之前排序“02”等。
有人有更好的方法来实现这个目标吗?
这是 Guava 版本(当您使用 Java 7 或更低版本时):
Ordering<String> ordering = Ordering.natural().nullsLast()
.onResultOf(Functions.forMap(map, null))
.compound(Ordering.natural());
这是使用纯 Comparator
的非 Guava 版本(在 JDK 8+ 上):
Comparator<String> comparator = Comparator
.<String, Integer>comparing(map::get, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(Comparator.naturalOrder());
PS。如您所见,Guava API 的类型推断更好(无需指定显式类型参数)。
我认为此解决方案应该可以解决您的问题。对于使用 ArrayList
s,我深表歉意——我在 Java 8 API 中找不到与 ImmutableMap
对应的任何文档。我还假设 natural 顺序表示 ASCII 顺序。希望这会有所帮助:)
//Values to be sorted
ArrayList<Object> values = new ArrayList<>();
values.add("red");
values.add("orange");
values.add("orange");
values.add("yellow");
values.add("green");
values.add("blue");
values.add("indigo");
values.add("violet");
values.add(1); //I added 1 to verify output
//List containing order of known values
ArrayList<Object> knownOrder = new ArrayList<>();
knownOrder.add("red");
knownOrder.add(1);
knownOrder.add("green");
knownOrder.add("blue");
knownOrder.add(3);
ArrayList<Object> knownValues = new ArrayList<>();
ArrayList<Object> unknownValues = new ArrayList<>();
for (Object value: values) {
if (knownOrder.contains(value)) {
knownValues.add(value);
}else {
unknownValues.add(value);
}
}
//Sort known values in required order
Collections.sort(knownValues, (m1, m2)->knownOrder.indexOf(m1)-knownOrder.indexOf(m2));
//Sort unknown values in natural order
Collections.sort(unknownValues, (m1, m2)->m1.toString().charAt(0)-m2.toString().charAt(0));
//Combine the known and unknown values into one ArrayList
knownValues.addAll(unknownValues);
System.out.println(knownValues);
//Prints [red, 1, green, blue, indigo, orange, orange, violet, yellow]
我还应该提到:此解决方案不适用于字符串和原始包装器以外的对象。