Как сравнивать объекты в одном массиве - PullRequest
0 голосов
/ 08 июня 2018

У меня есть массив объектов, и я хочу найти дубликаты.Я сравниваю долготу / долготу и, к сожалению, значения не совсем совпадают.

Как найти дубликаты?

Мой пример кода:

var locations = [("Location_A", 49.5858, 9.123456), ("Location_B", 49.5858, 9.123456), ("Location_A", 49.5855, 9.123450), ...]

for location in locations {
    //Find duplicate based on longitude and latitude where values < 0.0004
}

Вв этом случае locations[0] и locations[2] должны быть определены как дубликаты.

Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 08 июня 2018

С кортежами работать нелегко, я рекомендую сначала обернуть ваши данные в пользовательский объект:

import CoreLocation

struct MyLocation: Hashable {
    let name: String
    let coordinate: CLLocation

    init(tuple: (String, Double, Double)) {
        name = tuple.0
        coordinate = CLLocation(latitude: tuple.1, longitude: tuple.2)
    }

    public static func == (lhs: MyLocation, rhs: MyLocation) -> Bool {
        return
            lhs.name == rhs.name
            && lhs.coordinate.distance(from: rhs.coordinate) < 1
    }

    public var hashValue: Int {
        return name.hashValue
    }
}

Как видите, я уже объявил Equatable, а также Hashable для простотыindexing.

Тогда мы можем использовать простое расширение Array:

extension Array where Element: Hashable {
    func distinct() -> [Element] {
        var uniqueValues: Set<Element> = []
        return self.filter {
            let (inserted, _) = uniqueValues.insert($0)
            return inserted
        }
    }
}

И использовать его для наших данных:

var locations = [("Location_A", 49.5858, 9.123456), ("Location_B", 49.5858, 9.123456), ("Location_A", 49.5855, 9.123450)]
let myLocations = locations
    .map { MyLocation(tuple: $0) }
    .distinct()
print(myLocations)

Обратите внимание, что я определил равенстводля двух объектов, когда они ближе, чем 1 метр.Это будет медленнее, чем простое сравнение долготы с долготой и широты с широтой, но также будет более точным.

0 голосов
/ 08 июня 2018

Вместо кортежей используйте пользовательскую структуру.Теперь вы можете сделать эту структуру Equatable, определяя == для этой структуры таким образом, чтобы учесть значение epsilon:

struct Loc : Equatable {
    let name : String
    let latitude : Double
    let longitude : Double
    static let epsilon = 0.0004
    static func ==(lhs:Loc, rhs:Loc) -> Bool {
        if lhs.name != rhs.name { return false }
        if abs(lhs.latitude - rhs.latitude) > epsilon { return false }
        if abs(lhs.longitude - rhs.longitude) > epsilon { return false }
        return true
    }
}

Давайте проверим его:

let loc1 = Loc(name: "Location_A", latitude: 49.5858, longitude: 9.123456)
let loc2 = Loc(name: "Location_A", latitude: 49.5855, longitude: 9.123450)
print(loc1 == loc2) // true

AtВ этот момент устоявшиеся методы устранения дубликатов будут воплощены в жизнь.

...