我需要根据过滤器列表对项目列表进行排序,这些过滤器按优先级排序。但是,这些过滤器来自API请求正文,因此可以更改。
我有一个Filter类
public class Filter {
private String fieldName;
private String order;
// Getters and Setters...
}
一些过滤器对象
Filter filter1 = new Filter("price", "desc");
Filter filter2 = new Filter("size", "asc");
我的Item类如下:
public class Item {
private String productName;
private double size;
private double price;
// Getters and Setters...
}
然后我必须对项目进行排序:
如果Item.price等于下一个Item,则比较它们的大小,依此类推...
我已经尝试为每个过滤器创建一个Comparator,但是无法链接它们,因此每个过滤器都自行对列表进行排序,而与先前的排序方法无关(有时将整个列表倒置)。
我也尝试在Item类上实现Comparable接口,但是接口方法compareTo
仅接受一个参数(下一个Item),而不接受规则列表。
因此给出了类似的项目列表
List<Item> items = new ArrayList<Item>(
new Item("foo", 10.0, 5.0),
new Item("bar", 6.0, 15.0),
new Item("baz", 7.0, 5.0)
);
以及类似的过滤器列表
List<Filter> filters = new ArrayList<Filter>(
new Filter("price", "desc"),
new Filter("size", "asc")
);
我希望结果是
List<Item> sortedItems = new ArrayList<Item>(
new Item("bar", 6.0, 15.0),
new Item("baz", 7.0, 5.0),
new Item("foo", 10.0, 5.0)
);
你能帮我吗?预先感谢!
重要提示:我对字段本身的比较没有问题。我的问题是制作一个动态比较器,该比较器根据过滤器列表更改其比较。
答案 0 :(得分:1)
我相信以下内容将为您正确链接给定变量过滤器比较项的比较器。它使用反射来调用吸气剂,并假定比较是双打。
如果不能保证它们是双精度的,请调整反射类型以将其转换为适用于所有用例的对象。
PropertyUtils.getProperty()是Apache Commons BeanUtils的一部分,可以通过选择获取值来代替,无论是通过反射还是静态比较器。
public class Filter {
// properties, constructors, getters, setters ...
public Comparator<Item> itemComparator() {
return (item1, item2) -> {
Double val1 = (Double) PropertyUtils.getProperty(item1, fieldName);
Double val2 = (Double) PropertyUtils.getProperty(item2, fieldName);
return (order.equals("asc") ? val1.compareTo(val2) : val2.compareTo(val1);
};
}
public static Comparator<Item> chainedItemComparators(List<Filter> filters) {
return filters.stream()
.map(Filter::itemComparator)
.reduce((item1, item2) -> 0, (f1, f2) -> f1.thenComparing(f2));
}
}
然后使用链接的比较器:
public static void main(String[] args) {
List<Filter> filters = new ArrayList<>(Arrays.asList(
new Filter("price", "desc"),
new Filter("size", "asc")
));
List<Item> items = new ArrayList<>(Arrays.asList(
new Item("bar", 6.0, 15.0),
new Item("baz", 7.0, 5.0),
new Item("foo", 10.0, 5.0)
));
items.sort(Filter.chainedItemComparators(filters));
}
答案 1 :(得分:0)
在基于价格和基于大小的初始实现的基础上,您可以组成比较器。
以下方法为给定的过滤器创建一个项目比较器:
//Preferring static implementations to reflection-based ones
//if there are too many fields, you may want to use a Map<String, Comparator<Item>>
static Comparator<Item> priceComparator = Comparator.comparing(Item::getPrice);
static Comparator<Item> sizeComparator = Comparator.comparingDouble(Item::getSize);
private static Comparator<Item> itemComparator(Filter filter) {
Comparator<Item> comparator = "price".equals(filter.getFieldName()) ?
priceComparator : sizeComparator;
if ("desc".equals(filter.getOrder()))
return comparator.reversed();
return comparator;
}
由此您可以从过滤器列表中链接比较器:
public static void main(String args[]) {
Comparator<Item> comparator = itemComparator(filters.get(0));
for (Filter f : filters.subList(1, filters.size())) {
comparator = comparator.thenComparing(itemComparator(f));
}
items.sort(comparator);
}
经过测试,我得到以下(预期)输出:
[[productName=bar, size=6.0, price=15.0],
[productName=baz, size=7.0, price=5.0],
[productName=foo, size=10.0, price=5.0]]