【问题标题】:Java sort object by list type propertyJava 按列表类型属性排序对象
【发布时间】:2015-05-26 17:42:03
【问题描述】:

我有以下物品:

public class Shipping {
    String name;
    List<Method> methods;
}

public class Method {
    String serviceType;
    String cost;
}

我有:

List<Shipping> shippings;

我想按照返回成本最低的方式对运费进行排序。

示例:

shipping: "Josh" with 2 methods: "Premium","5" and "Basic","3"
shopping: "Nash" with 2 methods: "Prem", "7" and "Base","2"

会这样排序:

shopping: "Nash" with 2 methods: "Base","2" and "Prem", "7"
shopping: "Josh" with 2 methods: "Basic","3" and "Premium","5"

我需要它返回具有最便宜方法成本的方法作为第一个方法,同时还对方法进行排序以首先具有最便宜的方法。

最好的方法是什么?我正在使用 Java 8,如果它有更好的解决方案,并且有 guava

编辑: 成本是一个浮点数。我需要将其保留为 String,因为它是我传递给 REST api 并且不希望客户端解析它的对象。

【问题讨论】:

    标签: java sorting guava


    【解决方案1】:

    我们将假设所有运输至少有 1 种方法。因此,您希望按成本对运输方式进行排序。所以让我们这样做:

    shippings.forEach(shipping -> {
        shipping.getMethods().sort(Comparator.comparing(Method::getCost));
    });
    

    然后,您希望按其方法的最低成本对运输列表进行排序。最低成本是第一种方法的成本,因为它们现在已排序:

    shippings.sort(Comparator.comparing(shipping -> shipping.getMethods().get(0).getCost()));
    

    请注意,这假设您希望按字典顺序比较成本。如果我怀疑成本实际上是一个数字,那么它应该存储在 Method 类中,而不是作为字符串。因此,将其设为 Integer 或 BigDecimal,或任何合适的类型。

    【讨论】:

    • 是的 - 成本是浮动的。但我宁愿将它保留为字符串,因为它是我传递给 REST api 并且不希望客户端解析它的对象。在那种情况下——你建议怎么写?
    • 如果是浮点数,则保留为浮点数。为什么客户端必须解析一个数字?通过将其设置为字符串,您会使客户端的生活更加变得困难:它将再次将 JSON 中的字符串转换为数字。无论如何,如果您真的想以不好的方式进行操作,请在比较时将字符串解析为浮点数。 IE。将Comparator.comparing(Method::getCost) 替换为Comparator.comparingDouble(method -&gt; Double.parseDouble(method.getCost()))
    • 谢谢 - 客户端只是显示它而不是转换它。它不做任何计算。我在某处读到休息对象应该以客户端不需要再次编辑它们的方式提供服务
    • 是的。 shipping.getMethods().get(0) 将抛出 IndexOutOfBoundsException。
    • 同意字段需要是浮点数。 OP 通过将其设为字符串来制造更多问题。
    【解决方案2】:

    您需要一个比较器或为 Method 类实现 Comparable,例如:

    public class Method implements Comparable<Method> {
        public int compareTo(Method thatMethod) {
            return Integer.compare(Integer.parseInt(this.cost), Integer.parseInt(thatMethod.getCost()));//if you need name then you could do this.cost.compareTo(thatMethod.getServiceType()); assuming serviceType can never be null 
        }
    }
    

    然后将您的列表排序为:

    Collections.sort(methods);
    

    【讨论】:

    • 由于java中的字符串是按字典顺序比较的,所以你也可以避免解析为Integer而使用this.cost.compareTo(other.getCost())
    • @francescoforesti 不,字典顺序不适用于数字。词典的意思,例如9 大于 10
    • @Radiodef 你是对的!但是,真正的问题是String 不是那种数据的正确类型..
    • 谢谢。如果成本实际上是浮动的怎么办?
    • 它不只是对方法进行排序吗?我需要在比较方法时对运输进行实际排序
    【解决方案3】:

    您可以定义新的Comparator 来定义您的排序标准,如下所示:

    Comparator<Shipping> shippingComparator = new Comparator<Shipping>{
    public int compare(Shipping obj1, Shipping obj2) {
        //your rules for comparing Shipping1, Shipping 2 goes here
        //return -1 when obj1 should be before obj2
        //return 1 when obj1 should be after obj2
        //return 0 when obj1 is equal to obj2 and relative position doesnt matter
    } 
    

    然后使用此比较器对您的列表进行排序:

    ArrayList<Shipping> shippings;
    //populate List
    Collections.sort(shippings, shippingComparator );
    

    【讨论】:

    • 方法比较我没明白怎么写
    • shippingComparator 用于排序运输清单。在比较器内部,您必须遍历methods 列表,找出最小成本,然后将此成本与其他对象的最小值进行比较。基于此比较返回 1,0,-1。例如,获取 Obj 1 的最低成本,并将其与 Obj 2 的最低成本进行比较。
    • 如果你也想在methods列表中排序,你可以为Method定义类似的比较器shippingComparator,然后使用这个比较器排序methods列表。
    【解决方案4】:

    您可以先对shippings 列表中每个Shipping 实例的methods 字段进行排序,然后按每个实例的methods 列表的第一个元素对shippings 列表进行排序:

    for (Shipping shipping : shippings)
        shipping.methods.sort((m1, m2) -> Integer.compare(m1.cost, m2.cost));
    
    shippings.sort((s1, s2) -> 
      Integer.compare(s1.methods.get(0).cost, s2.methods.get(0).cost));
    

    您可能需要做一些额外的工作将成本转换为整数,但总体思路是相同的。

    【讨论】:

    • 在我的例子中是浮点数。我该如何使用它?不是 sort 期待 int 吗?
    • @Dejel 它只是Double.compare 而不是Integer.compare
    【解决方案5】:

    我建议您阅读 Java 的订购 tutorial。您的要求似乎表明您希望按其Method 对每个Shipping 实例进行排序,而在其他地方您希望对您希望按字母顺序排序的Shipping 实例的集合进行排序,但您的内容并不完全清楚写好了。

    在任何情况下,一旦您阅读了教程,就很容易做到这一点。总之,您可以使用Comparator 或通过实现Comparable 来做到这一点,并在您的数据集上简单地调用Collections.sort(...)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-11
      • 2019-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-20
      相关资源
      最近更新 更多