【问题标题】:Kotlin Sorting a list of objects based on their coordinate( lat and long) using Haversine formulaKotlin 使用 Haversine 公式根据对象的坐标(纬度和经度)对对象列表进行排序
【发布时间】:2022-01-10 19:45:17
【问题描述】:

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

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()
}

我收到错误:公共开放乐趣的参数太多 !> sort(list: (Mutable)List!): Unit defined in java.util.Collections 在我的排序{}函数 我的 userProperty 必须是属性?因为 find{} 方法返回属性? 那么 Collections.sort() 不能排序属性?键入因为 SortPLaces 只接受 Comparator 而不是 Comparator 我该怎么办?

【问题讨论】:

  • new SortPlaces? Collections.sort?你把它和 Java 搞混了吗?
  • 如果你的代码找不到位置,你想要做什么,所以userProperty 为空?

标签: kotlin generics


【解决方案1】:

您的代码中有多个错误。要在 Kotlin 中创建一个新对象,您不必像在 Java 中那样编写单词 new。此外,正如您所注意到的,find 返回一个 可为空 类型 - 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 类。只需在数组上使用 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!
        }

    }
}

【讨论】:

  • 您能告诉我如何获取半径前 10 公里内的元素吗?
  • @KhoaBui 嗯...这不是你要求的,是吗?你的列表排序问题解决了吗?如果是这样,请考虑接受答案。如果您遇到更多问题,您可以发布另一个问题,显示您的确切位置。
猜你喜欢
  • 1970-01-01
  • 2021-10-22
  • 1970-01-01
  • 2014-11-06
  • 2014-01-22
  • 1970-01-01
  • 2021-05-08
  • 1970-01-01
  • 2015-01-03
相关资源
最近更新 更多