【问题标题】:Is there a specific way to use tuples as set elements in Swift?在 Swift 中,有没有一种特定的方法可以将元组用作集合元素?
【发布时间】:2016-01-04 11:23:19
【问题描述】:

我想对 x-y 网格中的坐标对元素进行设置操作。

例如{(0,0),(1,4),(1,5),(2,3)}{(2,3),(1,4),(2,6)} 联合 = {(0,0),(1,4),(1,5),(2,3),(2,6)}

不幸的是,我无法找到将元组插入 Swift 的 Set 命令的方法,因为它说它们不符合“可散列”协议。

错误:类型 '(Int, Int)' 不符合协议 'Hashable'

我相信我已经找到了解决办法,但它涉及大量代码。在我击中磨刀石之前,有没有一种我想念的简单方法?

【问题讨论】:

标签: ios swift set tuples


【解决方案1】:

给你:

class Pair {
    var x: Int
    var y: Int
    init(x: Int, y:Int){
        self.x = x
        self.y = y
    }

    func isExisted(inPairs pairs:[Pair]) -> Bool {
        for p in pairs {
            if p.y == self.y && p.x == self.x{
                return true
            }
        }
        return false
    }

    static func union (pairs1: [Pair], pairs2: [Pair]) -> [Pair] {
        var pairsFinal = [Pair]()

        for p in pairs1 {
            pairsFinal.append(p)
        }

        for p in pairs2 {
            if !p.isExisted(inPairs: pairsFinal){
                pairsFinal.append(p)
            }
        }
        return pairsFinal
    }
}

let pari1 = Pair(x: 4, y: 7)
let pair2 = Pair(x: 5, y: 2)
let pair3 = Pair(x: 4, y: 7)
let pair4  = Pair(x: 3, y: 9)

let pairs1 = [pari1, pair2]
let pairs2 = [pair3, pair4]

let f = Pair.union(pairs1, pairs2: pairs2)

这是联合的结果:

【讨论】:

  • 谢谢威廉。是的,这是我想到的解决方法(或至少类似于)——你的更优雅。
  • 鉴于union 已经在标准库中由Set 实现,我认为在这里重新实现它没有什么意义。实现实现 Hashable 的自定义结构要容易得多。如果你明天决定你也想要交集,你也必须重新实现它。但如果你只实现一次 Hashable,你就可以免费获得其他所有内容。
【解决方案2】:

不要使用元组来表示点,而是使用内置类型CGPoint。您可以通过扩展 CGPoint 使其可散列:

import UIKit

extension CGPoint: Hashable {
    public var hashValue: Int {
        return self.x.hashValue << sizeof(CGFloat) ^ self.y.hashValue
    }
}

// Hashable requires Equatable, so define the equality function for CGPoints.
public func ==(lhs: CGPoint, rhs: CGPoint) -> Bool {
    return CGPointEqualToPoint(lhs, rhs)
}

现在 CGPoint 是可散列的,你可以在集合中使用它。例如:

let point1 = CGPoint(x: 0, y: 1)
let point2 = CGPoint(x: 0, y: 2)
let point3 = CGPoint(x: 1, y: 1)
let point4 = CGPoint(x: 3, y: 3)
let point5 = CGPoint(x: 3, y: 3)  // Intentionally the same as point4 to see the effect in union and difference.

let set1 = Set([point1, point2 , point5])
let set2 = Set([point4, point3])

let union = set1.union(set2) // -> {{x 0 y 2}, {x 3 y 3}, {x 0 y 1}, {x 1 y 1}}
let difference = set1.intersect(set2) // -> {{x 3 y 3}}

【讨论】:

  • 感谢阿比伦。对于那些阅读上述代码但没有立即理解的人(我没有)尝试:谷歌搜索:CG Point - 了解核心图形框架然后查看最初问题中提供的链接:stackoverflow.com/questions/31438210/…特别是引用了题为“实现 Swift 的 Hashable 协议”的文章
  • 很高兴您花时间理解我的示例。初学者很容易接受答案并应用它。通过学习如何为自己学习,您正在成为一名更好的程序员..
  • CGPoint 在这里可能并不完全正确。如果我们像编译器那样从@MoonfacedBoon 的示例中推断类型,那么我们将得到[(Int, Int)]CGPoint,但是将您的整数参数转换为 CGFloats。这意味着在执行任何只是噪音的集合操作后,将强制转换回Int。根据输入值的选择,我还担心在设置操作期间可能出现浮点错误。
【解决方案3】:

您可以将struct 设为Hashable 类型:

struct Point: Hashable {
  let x: Int
  let y: Int
}

现在您有了一个可散列元组,可以使用普通的Set 操作:

let set1 = Set([
  Point(x:0,y:0),
  Point(x:1,y:4),
  Point(x:1,y:5),
  Point(x:2,y:3)
]) 

let set2 = Set([
  Point(x:2,y:3),
  Point(x:1,y:4),
  Point(x:2,y:6)
])

let setUnion = set1.union(set2)

/*
setUnion = {
  Point(x: 1, y: 5), 
  Point(x: 0, y: 0), 
  Point(x: 1, y: 4), 
  Point(x: 2, y: 3), 
  Point(x: 2, y: 6)
}
*/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-26
    • 1970-01-01
    • 2021-11-16
    • 2018-06-02
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多