【问题标题】:kotlin: sort List<T> with T being a classkotlin:对 List<T> 进行排序,其中 T 是一个类
【发布时间】:2021-12-25 14:55:44
【问题描述】:

我在 Kotlin 中定义了一个公共类:public class Edge(val v: Int, val u: Int, val weight: Double),它可以帮助我定义图的加权边。

现在,在另一个类中,我需要创建一个列表,我将其定义为 var Sides = mutableListOf&lt;Edge&gt;(),但我需要根据 Edge 的第三个参数(即 weight)按升序对列表进行排序。因此,如果我有清单:

Sides = {Edge(4, 8, 4.1), Edge(20, 9, 7.5), Edge(5, 4, 0.0)},就变成了:

边 = {边(5, 4, 0.0), 边(4, 8, 4.1), 边(20, 9, 7.5)}

有没有像.sort() 这样的函数可以用来订购这个列表?还是我必须为此手动创建排序方法的功能?

提前致谢

【问题讨论】:

    标签: list sorting kotlin


    【解决方案1】:

    对于像MutableList 这样的可变集合,您可以使用sortBy 函数对原始列表本身进行排序。

    sides.sortBy { it.weight }
    

    而且,如果您有像 List 这样的不可变集合,则可以使用返回新排序列表的 sortedBy 函数。

    val sortedList = sides.sortedBy { it.weight }
    

    此外,您还有sortByDescendingsortedByDescending 用于按降序排序。

    【讨论】:

      【解决方案2】:

      您正在寻找sortBy。给定T 的列表,sortBy 采用从TR 的映射函数(其中R 是某种类型,其中定义了排序)。考虑

      Sides.sortBy { n -> n.weight }
      

      【讨论】:

        【解决方案3】:

        您有两种基本方法:

        1. Edge一个自然排序。然后所有的排序函数都将默认使用它——就像其他任何可以使用排序的函数一样(例如 SortedMapbinarySearch() 方法中的键顺序)。

        您可以通过实现Comparable 接口来做到这一点。这只有一个方法,compareTo(),它可以很简单:

        public class Edge(val v: Int, val u: Int, val weight: Double) : Comparable<Edge> {
            override fun compareTo(other: Edge) = weight.compareTo(other.weight)
        }
        

        但是,这并没有为具有相同权重的实例提供一致的顺序,因此您可能还希望使用其他属性作为决胜局,例如:

            override fun compareTo(other: Edge)
                = weight.compareTo(other.weight).takeIf{ it != 0 }
                ?: v.compareTo(other.v).takeIf{ it != 0 }
                ?: u.compareTo(other.u)
        

        (实现这一点有一些微妙之处,特别是如果您没有同时覆盖 equals() 以直接对应。 Java documentation 值得一读。)

        请注意,data class 按其构造函数中的属性自动实现Comparable。所以你通常不需要担心订购。

        1. 排序时提供排序

        其他答案对此进行了讨论。也许最简单的方法是:

        sides.sortBy{ it.weight }
        

        虽然有很多选择,比如:

        sides.sortWith{ a, b -> a.weight.compareTo(b.weight) }
        

        或者您可以创建一个Comparator 实例,以便在必要时重复使用:

        val comparator = Comparator<Edge>{ o1, o2 -> o1.weight.compareTo(o2.weight) }
        sides.sortWith(comparator)
        

        同样,比较器可以与标准库中的许多函数一起使用,因此您可以避免重复权重比较代码。


        选择哪种方法取决于您的需求。

        如果您的边缘始终按重量排列是直观的,那么自然排序将是一个很好的选择。这对代码来说很简洁:您只需在一个地方实现Comparable(或者将您的类设为data class,并首先指定权重属性),然后您就可以享受到处订购的全部好处。 (当然,只有在您可以控制 Edge 源代码的情况下才能这样做。)

        另一方面,如果基于权重的排序特定于特定方法(如果您可能希望在其他地方有不同的排序),那么在排序时指定排序会更有意义。

        当然,如果需要,您可以同时进行这两种操作:您可以为对象提供适用于大多数事情的自然顺序,然后为特定操作指定不同的顺序。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-07-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-20
          相关资源
          最近更新 更多