如何在 java 中的条件下使用比较器
How to use Comparator with conditions in java
我正在尝试根据从 API 收到的排序键和排序顺序对列表进行排序。
例如,
我有一个带有 sortkey 和 sortorder 的列表,我需要根据它进行排序。
List<SortList> sortlist;
我有一个对象列表:
List<Employee> employee;
我可以使用
进行排序
Collections.sort(sourceList, Comparator
.comparing(Employee::getAge).reversed()
.thenComparing(Employee::getCount));
但我需要根据条件检查 sortfeild,并基于该条件仅考虑对字段进行排序。
例如:
if(排序键="name")
排序列表中的 sortbythatkey 按排序顺序
if(排序键="place")
sortbythat key from sortlist by the sort order
所以这里如果 sortlist 有名称和地点那么它应该同时按键和顺序排序
知道我怎样才能做到这一点吗?
排序列表包含:
{
"sortKey":"name",
"sortOrder":"ASC"
},
{
"sortKey":"place",
"sortOrder":"DESC"
}
要求像 SQL
中的 ORDER BY 一样将它们链接在一起
您可以创建一个方法,在传递排序键时提供正确的比较器:
public Comparator<Employee> getComparator(String sortKey) {
if("name".equals(sortKey)) {
return Comparator.comparing(Employee::getName);
} else if ("place".equals(sortKey) {
return Comparator.comparing(Employee::getPlace);
} else {
throw new IllegalArgumentException();
}
}
简单地调用它:
Collections.sort(sourceList, getComparator(sortKey).reversed()
.thenComparing(Employee::getCount));
虽然您也可以自己编写,但我发现最好将 "standard" 部分委派出去,只编写与此不同的部分。
如果您发现自己有很多这样的排序键,那么更合适的方法是使用映射:
private static final Map<String, Comparator<Employee>> COMPARE_MAP = new HashMap<>() {{
put.("name", Comparator.comparing(Employee::getName));
put.("place", Comparator.comparing(Employee::getPlace));
}});
public Comparator<Employee> getComparator(String sortKey) {
if(COMPARE_MAP.containsKey(sortKey)) {
return COMPARE_MAP.get(sortKey);
} else {
throw new IllegalArgumentException();
}
}
反射也是一种选择,但我会谨慎使用反射,除非不这样做变得不切实际。在这种情况下,您可以创建自己的注释来确定 class Employee 的哪些字段可用于排序。
假设sortlist
是一个SortCriteria
的列表,就是这样的class:
class SortCritera {
private String key;
private String order;
public String getKey() {
return key;
}
public String getOrder() {
return order;
}
// constructors, setters...
}
您首先需要一个 HashMap<String, Comparator<Employee>>
来存储每个可能的键的所有相应比较器:
HashMap<String, Comparator<Employee>> comparators = new HashMap<>();
comparators.put("name", Comparator.comparing(Employee::getName));
comparators.put("age", Comparator.comparing(Employee::getAge));
// ...
然后你可以遍历 sortlist
并继续调用 thenComparing
:
Comparator<Employee> comparator = comparators.get(sortlist.get(0).getKey());
if (sortlist.get(0).getOrder().equals("DESC")) {
comparator = comparator.reversed();
}
for(int i = 1 ; i < sortlist.size() ; i++) {
if (sortlist.get(i).getOrder().equals("DESC")) {
comparator = comparator.thenComparing(comparators.get(sortlist.get(i).getKey()).reversed());
} else {
comparator = comparator.thenComparing(comparators.get(sortlist.get(i).getKey()));
}
}
// now you can sort with "comparator".
正如 Holger 所建议的,您也可以使用 Stream API 来执行此操作:
sortlist.stream().map(sc -> {
Comparator<Employee> c = comparators.get(sc.getKey());
return sc.getOrder().equals("DESC")? c.reversed(): c;
}).reduce(Comparator::thenComparing)
.ifPresent(x -> Collections.sort(originalList, x));
我正在尝试根据从 API 收到的排序键和排序顺序对列表进行排序。 例如, 我有一个带有 sortkey 和 sortorder 的列表,我需要根据它进行排序。
List<SortList> sortlist;
我有一个对象列表:
List<Employee> employee;
我可以使用
进行排序Collections.sort(sourceList, Comparator
.comparing(Employee::getAge).reversed()
.thenComparing(Employee::getCount));
但我需要根据条件检查 sortfeild,并基于该条件仅考虑对字段进行排序。
例如:
if(排序键="name") 排序列表中的 sortbythatkey 按排序顺序
if(排序键="place") sortbythat key from sortlist by the sort order
所以这里如果 sortlist 有名称和地点那么它应该同时按键和顺序排序
知道我怎样才能做到这一点吗?
排序列表包含:
{
"sortKey":"name",
"sortOrder":"ASC"
},
{
"sortKey":"place",
"sortOrder":"DESC"
}
要求像 SQL
中的 ORDER BY 一样将它们链接在一起您可以创建一个方法,在传递排序键时提供正确的比较器:
public Comparator<Employee> getComparator(String sortKey) {
if("name".equals(sortKey)) {
return Comparator.comparing(Employee::getName);
} else if ("place".equals(sortKey) {
return Comparator.comparing(Employee::getPlace);
} else {
throw new IllegalArgumentException();
}
}
简单地调用它:
Collections.sort(sourceList, getComparator(sortKey).reversed()
.thenComparing(Employee::getCount));
虽然您也可以自己编写,但我发现最好将 "standard" 部分委派出去,只编写与此不同的部分。
如果您发现自己有很多这样的排序键,那么更合适的方法是使用映射:
private static final Map<String, Comparator<Employee>> COMPARE_MAP = new HashMap<>() {{
put.("name", Comparator.comparing(Employee::getName));
put.("place", Comparator.comparing(Employee::getPlace));
}});
public Comparator<Employee> getComparator(String sortKey) {
if(COMPARE_MAP.containsKey(sortKey)) {
return COMPARE_MAP.get(sortKey);
} else {
throw new IllegalArgumentException();
}
}
反射也是一种选择,但我会谨慎使用反射,除非不这样做变得不切实际。在这种情况下,您可以创建自己的注释来确定 class Employee 的哪些字段可用于排序。
假设sortlist
是一个SortCriteria
的列表,就是这样的class:
class SortCritera {
private String key;
private String order;
public String getKey() {
return key;
}
public String getOrder() {
return order;
}
// constructors, setters...
}
您首先需要一个 HashMap<String, Comparator<Employee>>
来存储每个可能的键的所有相应比较器:
HashMap<String, Comparator<Employee>> comparators = new HashMap<>();
comparators.put("name", Comparator.comparing(Employee::getName));
comparators.put("age", Comparator.comparing(Employee::getAge));
// ...
然后你可以遍历 sortlist
并继续调用 thenComparing
:
Comparator<Employee> comparator = comparators.get(sortlist.get(0).getKey());
if (sortlist.get(0).getOrder().equals("DESC")) {
comparator = comparator.reversed();
}
for(int i = 1 ; i < sortlist.size() ; i++) {
if (sortlist.get(i).getOrder().equals("DESC")) {
comparator = comparator.thenComparing(comparators.get(sortlist.get(i).getKey()).reversed());
} else {
comparator = comparator.thenComparing(comparators.get(sortlist.get(i).getKey()));
}
}
// now you can sort with "comparator".
正如 Holger 所建议的,您也可以使用 Stream API 来执行此操作:
sortlist.stream().map(sc -> {
Comparator<Employee> c = comparators.get(sc.getKey());
return sc.getOrder().equals("DESC")? c.reversed(): c;
}).reduce(Comparator::thenComparing)
.ifPresent(x -> Collections.sort(originalList, x));