【问题标题】:Sorting TreeMaps by value按值对 TreeMap 进行排序
【发布时间】:2021-02-19 19:34:22
【问题描述】:

我希望按特定的 Customer 属性对 Customer 对象的 TreeMap 进行排序。 TreeMap 是这样定义的:

private TreeMap<Long,Customer> customerMap = new TreeMap<>();

Long 是存储的客户 ID 的类型。

我编写了一个函数来创建一个新的 TreeMap 并将一个 Comparator 传递给它的构造函数,该构造函数获取映射条目及其值,用于比较特定字段。

public Customer[] getCustomersByName() {
    TreeMap<Long,Customer> sortByName = new TreeMap<> (

        new Comparator<Map.Entry<Long,Customer>>() {
            @Override public int compare(Map.Entry<Long,Customer> cus1, Map.Entry<Long,Customer> cus2) {
                return cus1.getValue().getLastName().compareTo(cus2.getValue().getLastName());
            }
        }
    );
    sortByName.putAll(customerMap);
    
    // sortByName to Customer[] and return.

}

这不起作用并抛出:无法在第 2 行推断 TreeMapJava(16778094) 的类型参数。

也许,问题在于 Comparator 使用 > 来比较 TreeMap,这就是问题所在。

我将如何解决这个问题以按值排序但保持 customerMap 类型不变?

我知道 TreeMap 仅按键排序。这项工作是否有更好的数据结构,以便我可以存储一堆 Customer 对象并按不同的 Customer 属性对它们进行排序,而操作成本不会太高(最好不是多项式)?

【问题讨论】:

    标签: java sorting generics treemap


    【解决方案1】:

    设置第二个 TreeMap,使用客户的姓氏作为键:

    TreeMap<String,Customer> sortByName  = new TreeMap<>();
    TreeMap<Long,Customer> sortByID = new TreeMap<>();
    ----------------
    sortByName.put(customer.getLastName(), customer);
    sortByID.put(new Long(customer.getID()), customer);
    ----------------
    return sortByName.values().toArray( new Customer[sortByName.size()] );
    '''
    

    【讨论】:

    • 但是为什么呢? OP 之后的结果是排序的Customer[],实现这一点更容易
    • @Eugene 以哪种方式更容易?第二个 TreeMap(按姓氏排序)和流都实现了相同的结果,尽管使用不同的方法。
    • 当其中一个完全未使用时,为什么要填写两个TreeMaps?顺便说一句,您不应该为传递给toArray 的数组指定大小。使用sortByName.values().toArray( new Customer[0] )。指定大小是基于假设的过早优化。如果您想知道实际结果,请阅读this excellent article。顺便说一下,最快的排序是Customer[] array = map.values().toArray(new Customer[0]); Arrays.sort(array, Comparator.comparing(Customer::getLastName)); return array;
    • @BigGuy 看来,您在阅读和理解文章时遇到了困难。它确实不是说预先调整数组大小更好;它清楚地表明 IntelliJ IDEA 15 和 PMD 5.4.1 等工具提出了此类声明,然后继续验证这些声明(这就是整篇文章的内容)并发现它们是错误的。由于这些工具的作者在文章发表后确实阅读并理解了文章,因此他们最近的版本不再建议这样做,而是建议使用零大小的数组。
    • 现在您已经了解使用零大小的数组实际上更快,(值得注意的是,没有任何改变,这就是为什么最新添加的 Collection.toArray(IntFunction) 只是创建一个零大小的数组并委托给toArray(T[]),甚至在文档中提到),我们可以得出最相关的事情:collection.toArray(new Type[0])collection.toArray(new Type[collection.size()]) 更简单,更不容易出错
    【解决方案2】:

    这对于流来说相当容易:

    Customer[] cust =
        customerMap.values()
                   .stream()
                   .sorted(Comparator.comparing(Customer::getName))
                   .toArray(Customer[]::new);
    

    您只需要根据您的示例对 进行排序,那么当您唯一关心的是排序(按名称)Customer[] 时,为什么还要对 TreeMap 进行反向排序?

    【讨论】:

    • 谢谢。我做了我所做的一切,因为我实际上被一个数据结构类分配了一些项目,并且集合的使用受到限制。我需要实现该结构并从头开始对其进行排序。我认为树形图是个好主意,因为它们在放入对象后已经按自然顺序排序。但我确实忘记了,我只能使用比较器按键排序。 @Big Guy 的回答在这种情况下可能更合适,但我想要更简洁的东西,也想避免浪费空间。您对我的情况有什么建议吗?
    • @sealion 过于简洁的问题之一是您创建了只写代码。你写的时候看起来不错,但以后再编辑它就成了问题。尽管我的一些代码可能很冗长,但以后(应该)很容易理解。当然还有奇怪的评论:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-06
    • 2022-12-09
    • 2021-01-04
    • 2013-11-03
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    相关资源
    最近更新 更多