【问题标题】:Swift: Is there a faster way to hash an array of Ints than "\(array)"斯威夫特:有没有比“\(数组)”更快的方法来散列一个整数数组
【发布时间】:2017-08-09 00:22:30
【问题描述】:

我想实现一个Dictionary,其中的键是String。

字符串键是通过字面连接Int 的数组生成的(它基本上是一个地址)。

即地址 [0, 10, 32] 的哈希值为“01032”。

值永远不会超过 255——事实上我可以使用 [UInt8]。

我在 XCode 中做了一个小测试,并获得了不错的性能。 0.036 秒:

func testPerformance() {
    let address = [10, 176, 12] //should become "1017612"
    self.measure {
         for _ in 0..<10_000 {
             let key = "\(address[0])\(address[1])\(address[2])"
         }
    }
}

我的问题:是否有更轻量级的 String 类型或方法可以比这更快地完成我想要的操作?据我了解,Swift 的 String 类是相当重量级的,在下面添加了各种字符信息:

https://medium.com/@tonyallevato/strings-characters-and-performance-in-swift-a-deep-dive-b7b5bde58d53

【问题讨论】:

  • 那么你的实际代码在哪里?
  • 已更新。谢谢。
  • 如果您正在寻找性能,为什么要使用计算字符串作为字典键?这些地址可以多长时间? (它们只是表示为 4 个 UInt8 的数组的 IPv4 地址吗?)
  • 为什么不使用实现 Hashable 的结构体?
  • 或者为什么不使用 Ints 作为键??

标签: swift string performance


【解决方案1】:

如果您的应用程序对性能敏感,那么您可能希望避免对固定为具有两个或三个成员的数据使用数组。数组在堆上分配了缓冲区,这些缓冲区需要进行引用计数。这两个事实都有性能影响。在绝大多数情况下它们可以忽略不计,但在处理大量数据(例如网络切换逻辑)的紧密循环中,您希望避免它们。

试试这样的:

struct TwoByteAddress: Hashable {
    let a: UInt8
    let b: UInt8

    init(_ a: UInt8, _ b: UInt8) {
        self.a = a
        self.b = b
    }

    static func ==(lhs: TwoByteAddress, rhs: TwoByteAddress) -> Bool {
        return lhs.a == rhs.a && lhs.b == rhs.b
    }

    var hashValue: Int {
        return Int(a) << 8 | Int(b)
    }
}

struct ThreeByteAddress: Hashable {
    let twoByteAddress: TwoByteAddress
    let c: UInt8

    init(_ a: UInt8, _ b: UInt8, _ c: UInt8) {
        self.twoByteAddress = TwoByteAddress(a, b)
        self.c = c
    }

    static func ==(lhs: ThreeByteAddress, rhs: ThreeByteAddress) -> Bool {
        return lhs.twoByteAddress == rhs.twoByteAddress && lhs.c == rhs.c
    }

    var hashValue: Int {
        return twoByteAddress.hashValue << 8 | Int(c)
    }
}

【讨论】:

  • 谢谢!是的,这是用于处理网络内容。传入的数据需要汇集到存储桶中。存储桶(字典)是当这个地址进来时需要通知的所有不同对象的列表。它有点像 NotificationCenter,但我自己维护观察者列表。
  • @MH175 那么这应该可以解决问题!应该非常快,因为这些结构是堆分配的。此外,hashValue 计算生成和连接这些字符串的速度要快得多
  • @MH175 您需要能够处理 2 字节和 3 字节地址的异构集合吗?
  • 是的——实际上最多 4 个字节。例如,我可以为所有以 255 开头的地址做 1 个字节,涵盖 [255, x, x, x]。或者我可以更深一层,做 [255, 0] 涵盖 [255, 0, x, x] 等。
  • @MH175 等等,这些只是子网掩码吗?
【解决方案2】:

我不明白为什么你首先要花费所有的开销来制作一个字符串。你有小的 Int,所以为什么不计算一个唯一的 Int 作为键:

let address = [10, 176, 12]
let key = address[0] * 255 * 255 + address[1] * 255 + address[2]

这是非常快速和自散列的,并且可以通过规则轻松提取原始组件。

或者,您可以使用三个 Int 属性的自定义结构,您已经在其上实现了 Hashable(根据相同的规则)和 Equatable(根据明显的规则)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-31
    • 1970-01-01
    • 2016-06-16
    • 1970-01-01
    • 1970-01-01
    • 2020-02-26
    • 2014-09-23
    • 1970-01-01
    相关资源
    最近更新 更多