【问题标题】:Sort a list of objects based on an unknown number of keys根据未知数量的键对对象列表进行排序
【发布时间】:2018-08-14 14:52:38
【问题描述】:

如果您知道传入的键或至少传入的键数,我已经看到了很多对对象列表进行排序的方法。 问题是在我的情况下,我不知道用户是否会发送 1 个或 10 个密钥。

目前我对每个键的数量都有一个巨大的 switch 语句,但显然它的扩展性非常大。它只是将一堆“thenComparing”链接在一起。

我在这里找到了一个示例,看起来很有帮助,但我不知道如何构建比较器流。

How-to chain and apply a stream of comparators?

寻找一个链接或任何可以填补有关如何做到这一点的空白的信息。

这一切都来自一个调用 web 服务的用户,他们会像这样调用它

https://host.com/path?sort=[{"attribute1": "ASC"}, {"attribute2": "DESC"}]

【问题讨论】:

  • 排序的决定因素是什么?例如,这些项目将如何排序:“A”、“B”、“ABC”、“BC”?
  • 用户如何告诉你的代码键是什么?
  • 你知道Comparator<Foo> cmp = Comparator.comparing(Foo::getA).thenComparing(Foo::getB).thenComparing(Foo::getC);Comparator<Foo> cmp = Comparator.comparing(Foo::getA); cmp = cmp.thenComparing(Foo::getB); cmp = cmp.thenComparing(Foo::getC);是一样的,循环起来很容易,对吧?
  • @Andreas 总的来说你是对的,问题是将这些字段设置为Function(我认为这些字段可能是intString 等)......最初我认为关于Map<String, Function<Person, String>> map = new HashMap<>(); map.put("name", Person::getName); 并根据密钥获取要提供给Comparator.comparingFunction,但这仅适用于字符串属性
  • @Lino 更简单:) 但你给了aha moment,谢谢

标签: java java-8


【解决方案1】:

假设你有这样一个实体:

static class Person {
    private final int age;

    private final String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }
}

您可以定义所有字段并将它们映射到某个比较器:

Map<String, Comparator<Person>> map = new HashMap<>();
map.put("name_ASC", Comparator.comparing(Person::getName));
map.put("name_DESC", Comparator.comparing(Person::getName).reversed());

map.put("age_ASC", Comparator.comparingInt(Person::getAge));
map.put("age_DESC", Comparator.comparingInt(Person::getAge).reversed());

然后有了您的意见,您可以这样做:

Comparator<Person> all = Stream.of("name_ASC", "age_DESC") // for example
            .map(map::get)
            .reduce(Comparator::thenComparing)
            .orElse((a, b) -> 0); // or whatever you think appropriate

在这之后对它们进行排序显然是不费吹灰之力的:

 List<Person> persons = List.of(new Person(20, "Bob"), new Person(30, "Rose"));

 // or Collections.sort(persons, all)
 // persons.sort(all)
 persons.stream().sorted(all).collect(Collectors.toList());

【讨论】:

  • 这很清楚。我可能最终会接受这一点,只是想破解类似的东西。感谢所有的 cmets 和回答!
  • 很好的答案 +1,如果不关心初始列表,那么persons.sort(all) 就足够了
  • 也有效,这将使persons 保持不变,所以我想这将取决于情况
【解决方案2】:

如果你可以建立一个比较器列表,你可以使用这样的东西:

public class MultiComparator<T> implements Comparator<T> {

    private final List<Comparator<T>> comparators;

    MultiComparator(List<Comparator<T>> comparators){
        this.comparators = comparators;
    }

    @Override
    public int compare(T t1, T t2) {
        int r = 0;
        for(Comparator c : comparators){
            r = c.compare(t1,t2);
            if(r != 0){
                return r;
            }
        }
        return r;
    }

}

(虽然不是很 Java 8)

【讨论】:

    猜你喜欢
    • 2012-05-19
    • 2015-01-03
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 1970-01-01
    • 2019-02-11
    • 2023-04-01
    • 2018-12-08
    相关资源
    最近更新 更多