如何比较一个数组中的对象

时间:2018-06-08 18:25:01

标签: arrays swift duplicates coordinates

我有一个对象数组,我想找到重复项。我比较了经度/经度,不幸的是,这些数值并不完全相等。

如何找到重复项?

我的示例代码:

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 :(得分:3)

使用自定义结构代替元组。现在你可以使该结构成为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

在那时,用于消除重复的成熟技术将会生动起来。

答案 1 :(得分:3)

元组不易使用,我建议首先将数据包装到自定义对象中:

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

正如您所看到的,我已经声明EquatableHashable以便于索引。

然后我们可以使用简单的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米时,我已经为两个对象定义了相等性。这比简单地将经度与经度和纬度与纬度进行比较要慢,但它也会更精确。