【问题标题】:Sort collection according to user custom input by single or multiple attributes根据用户自定义输入按单个或多个属性对集合进行排序
【发布时间】:2021-08-11 07:36:58
【问题描述】:

我有 Item 对象的集合,Item 类如下 ->

class Item {
  String id;
  String brand;
  Integer price;
  Date publishedDate;
}

现在,我想根据用户输入进行排序。用户可以根据自己的选择进行排序,如品牌、价格或发布日期,甚至可以使用多个参数。比如品牌和价格或价格和发布日期。

我已经看到 Comparator 按多个参数排序,但它也受到限制并且具有预定义的参数。所以基本上用户可以通过任何输入排序,排序机制可以在不更改任何代码的情况下处理。

我得到了一些使用战略设计模式的提示,但无法在此处实施以解决它。

【问题讨论】:

  • 这些数据来自哪里?通过 JPA?

标签: java spring sorting jpa collections


【解决方案1】:

您可以为每个字段使用静态 Map 作为 Comparator 并以此构建组合 Comparator: 您仍然必须使比较器为空安全并检查字段名称...

class Item {
    String id;
    String brand;
    Integer price;
    Date publishedDate;

    public Item(String id, String brand, Integer price, Date publishedDate) {
        super();
        this.id = id;
        this.brand = brand;
        this.price = price;
        this.publishedDate = publishedDate;
    }

    static Map<String, Comparator<Item>> comparatorMap = new HashMap<String, Comparator<Item>>() {
        {
            put("id", new Comparator<Item>() {
                @Override
                public int compare(Item o1, Item o2) {
                    return o1.id.compareTo(o2.id);
                }
            });
            put("brand", new Comparator<Item>() {
                @Override
                public int compare(Item o1, Item o2) {
                    return o1.brand.compareTo(o2.brand);
                }
            });
            put("price", new Comparator<Item>() {
                @Override
                public int compare(Item o1, Item o2) {
                    return o1.price.compareTo(o2.price);
                }
            });
            put("publishedDate", new Comparator<Item>() {
                @Override
                public int compare(Item o1, Item o2) {
                    return o1.publishedDate.compareTo(o2.publishedDate);
                }
            });
        }
    };

    @Override
    public String toString() {
        return "Item [id=" + id + ", brand=" + brand + ", price=" + price + ", publishedDate=" + publishedDate + "]";
    }

    static class ItemComparator implements Comparator<Item> {
        private List<Comparator<Item>> comparators;

        ItemComparator(String... fields) {
            comparators = new ArrayList<>();
            for (String field : fields) {
                comparators.add(comparatorMap.get((field)));
            }
        }

        @Override
        public int compare(Item o1, Item o2) {
            int result = 0;
            for (Comparator comparator : comparators) {
                result = comparator.compare(o1, o2);
                if (result != 0) {
                    return result;
                }
            }
            return result;
        }

    }

    static List<Item> sort(List<Item> list, String... fields) {
        Collections.sort(list, new ItemComparator(fields));
        return list;
    }

    public static void main(String[] args) {
        List<Item> list = new ArrayList<>();
        list.add(new Item("B", "A", 5, new Date()));
        list.add(new Item("A", "B", 7, new Date()));

        sort(list, "id", "price");
        System.out.println(list);
    }
}

编辑

使用比较/然后比较的版本

使用反射获取 getter 时可以省略映射...

class Item {
    String id;
    String brand;
    Integer price;
    Date publishedDate;

    public Item(String id, String brand, Integer price, Date publishedDate) {
        super();
        this.id = id;
        this.brand = brand;
        this.price = price;
        this.publishedDate = publishedDate;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    public Date getPublishedDate() {
        return publishedDate;
    }

    public void setPublishedDate(Date publishedDate) {
        this.publishedDate = publishedDate;
    }

    static Map<String, Comparator<Item>> comparatorMap = new HashMap<String, Comparator<Item>>() {
        {
            put("id", Comparator.comparing(Item::getId));
            put("brand", Comparator.comparing(Item::getBrand));
            put("price", Comparator.comparing(Item::getPrice));
            put("publishedDate", Comparator.comparing(Item::getPublishedDate));
        }
    };

    static List<Item> sort(List<Item> list, String... fields) {
        Comparator comparator = null;
        for (String field : fields) {
            comparator = (comparator == null) ?  comparatorMap.get((field))
                : comparator.thenComparing(comparatorMap.get((field)));
        }

        if (comparator != null) {
            Collections.sort(list, comparator);
        }
        return list;
    }

    @Override
    public String toString() {
        return "Item [id=" + id + ", brand=" + brand + ", price=" + price + ", publishedDate=" + publishedDate + "]";
    }

    public static void main(String[] args) {
        List<Item> list = new ArrayList<>();
        list.add(new Item("B", "A", 5, new Date()));
        list.add(new Item("A", "B", 7, new Date()));

        sort(list, "id", "price");
        System.out.println(list);
    }
}

【讨论】:

  • ...或者您可以使用现代 Java 和 Comparator.comparing() / thenComparing()
  • @crizzis Tahnks 指出了这一点,之前没用过
  • 感谢 @Turo 在这里帮助我
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-17
  • 1970-01-01
  • 2011-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多