Kotlin 使用 Haversine 公式根据对象的坐标(纬度和经度)对对象列表进行排序

Kotlin Sorting a list of objects based on their coordinate( lat and long) using Haversine formula

我想根据经纬度对列表进行排序... 这是我的代码:

import java.util.*
import com.google.gson.GsonBuilder
import java.io.File
import java.io.InputStream
import java.util.Comparator

data class Property(val Pcode: Int, val Locality: String, val State: String, val Comments: String, val Category: String, val Longitude: Double, val Latitude: Double)


class SortPlaces(currentLatitude: Double, currentLongitude: Double) : Comparator<Property> {
    var currentLat: Double
    var currentLng: Double
    override fun compare(property1: Property, property2: Property): Int {
        val lat1: Double = property1.Latitude
        val lon1: Double = property1.Longitude
        val lat2: Double = property2.Latitude
        val lon2: Double = property2.Longitude
        val distanceToPlace1 = distance(currentLat, currentLng, lat1, lon1)
        val distanceToPlace2 = distance(currentLat, currentLng, lat2, lon2)
        return (distanceToPlace1 - distanceToPlace2).toInt()
    }

    fun distance(fromLat: Double, fromLon: Double, toLat: Double, toLon: Double): Double {
        val radius = 6378137.0 // approximate Earth radius, *in meters*
        val deltaLat = toLat - fromLat
        val deltaLon = toLon - fromLon
        val angle = 2 * Math.asin(
            Math.sqrt(
                Math.pow(Math.sin(deltaLat / 2), 2.0) +
                        Math.cos(fromLat) * Math.cos(toLat) *
                        Math.pow(Math.sin(deltaLon / 2), 2.0)
            )
        )
        return radius * angle
    }

    init {
        currentLat = currentLatitude
        currentLng = currentLongitude
    }
}

fun main(args: Array<String>) {
    val command = Scanner(System.`in`)
    val running = true

    while (running) {

        val inputStream: InputStream = File("./src/main/kotlin/suburbs.json").inputStream()
        val inputString = inputStream.bufferedReader().use { it.readText() }
        val gson = GsonBuilder().create()
        val packagesArray = gson.fromJson(inputString , Array<Property>::class.java).toList()

        println("Please enter a suburb name: ")
        val suburbName = command.nextLine()

        println("Please enter the postcode: ")
        val postcode = command.nextLine()

        val userProperty: Property? = packagesArray.find{ it.Locality.toLowerCase().equals(suburbName.toLowerCase()) && it.Pcode == postcode.toInt()}

        //sort the list, give the Comparator the current location
        Collections.sort(packagesArray, new SortPlaces(userProperty.Latitude, userProperty.Longitude));


    }
    command.close()
}

我收到错误:public 的参数太多 open fun !> sort(list: (Mutable)List!): Unit defined in java.util.Collections 在我的排序{}函数 我的用户 属性 必须是 属性?因为 find{} 方法 return 属性? 那么Collections.sort()不能排序属性? type 因为 SortPLaces 只接受 Comparator 而不是 Comparator<属性?> 我该怎么办?

您的代码中存在多个错误。要在 Kotlin 中创建一个新对象,您不需要像在 Java 中那样写单词 new。另外,正如您所注意到的,find returns 一个 nullable 类型 - Property?。使用 userProperty 时需要检查空值。毕竟,Property不一定能找到符合您要求的标准。

if (userProperty != null) {
    Collections.sort(packagesArray, SortPlaces(userProperty.Latitude, userProperty.Longitude))
} else {
    // no property is found! Think about what you should do in such a case
}

由于您是按顺序对列表进行排序,因此在反序列化 JSON 时,不应使用 toList 创建不可变列表,而应使用 MutableList:

val packagesArray = gson.fromJson(inputString, Array<Property>::class.java).toMutableList()

此外,您似乎使用了很多 Java API。在 Kotlin 中,您使用的许多 Java API 都有更多惯用的 Kotlin 对应项。要对列表进行排序,您根本不需要 SortPlaces class。只需在数组上使用 sortBy,然后在 lambda 中调用 distance 函数。

data class Property(
    val pcode: Int,
    val locality: String,
    val state: String,
    val comments: String,
    val category: String,
    val longitude: Double,
    val latitude: Double,
    )


fun distance(fromLat: Double, fromLon: Double, toLat: Double, toLon: Double): Double {
    val radius = 6378137.0 // approximate Earth radius, *in meters*
    val deltaLat = toLat - fromLat
    val deltaLon = toLon - fromLon
    val angle = 2 * asin(
        sqrt(
            sin(deltaLat / 2).pow(2.0) +
                    cos(fromLat) * cos(toLat) *
                    sin(deltaLon / 2).pow(2.0)
        )
    )
    return radius * angle
}

fun main(args: Array<String>) {
    val running = true

    while (running) {
        val inputStream = File("./src/main/kotlin/suburbs.json").inputStream()
        val inputString = inputStream.bufferedReader().use { it.readText() }
        val gson = GsonBuilder().create()
        val packagesArray = gson.fromJson(inputString , Array<Property>::class.java).toMutableList()

        println("Please enter a suburb name: ")
        val suburbName = readLine()

        println("Please enter the postcode: ")
        val postcode = readLine()

        val userProperty = packagesArray.find {
            it.locality.lowercase() == suburbName?.lowercase() && it.pcode == postcode?.toInt()
        }

        //sort the list, give the Comparator the current location
        if (userProperty != null) {
            packagesArray.sortBy {
                distance(userProperty.latitude, userProperty.longitude, it.latitude, it.longitude)
            }
        } else {
            // did not find such a property!
        }

    }
}