【问题标题】:Histogram of Array in SwiftSwift中数组的直方图
【发布时间】:2018-10-03 09:14:43
【问题描述】:

我正在尝试编写一个在Array 上运行的通用直方图函数,但由于类型“元素”不符合协议“哈希”,我遇到了困难。

extension Array {
    func histogram() -> [Array.Element: Int] {
        return self.reduce([Array.Element: Int]()) { (acc, key) in
                let value = (acc[key] == nil) ? 1 : (acc[key]! + 1)
                return acc.dictionaryByUpdatingKey(key: key, value: value)
        }
    }
}

dictionaryByUpdatingKey(...) 对现有字典进行如下变异:

extension Dictionary {
    func dictionaryByUpdatingKey(key: Dictionary.Key, value: Dictionary.Value) -> Dictionary {
        var mutableSelf = self
        let _ = mutableSelf.updateValue(value, forKey: key)
        return mutableSelf
    }
}

我尝试将Array.Element 替换为AnyHashable,然后强制使用key as! AnyHashable,但这看起来很混乱,返回类型最好与Array.Element 的类型相同,而不是AnyHashable

我希望使用Array 扩展如下:

let names = ["Alex", "Alex", "James"]
print(names.histogram()) // ["James": 1, "Alex": 2]

let numbers = [2.0, 2.0, 3.0]
print(numbers.histogram()) // [3.0: 1, 2.0: 2]

【问题讨论】:

标签: ios arrays swift histogram


【解决方案1】:

通用 where 子句where Element: Hashable 添加到您的扩展中:

extension Sequence where Element: Hashable {
    func histogram() -> [Element: Int] {
        return self.reduce([Element: Int]()) { (acc, key) in
            let value = acc[key, default: 0] + 1
            return acc.dictionaryByUpdatingKey(key: key, value: value)
        }
    }
}

我还采纳了@MartinR 的建议,即使用新的default 值进行字典查找。


使用reduce(into:_:),您可以更简单有效地做到这一点:

extension Sequence where Element: Hashable {
    func histogram() -> [Element: Int] {
        return self.reduce(into: [:]) { counts, elem in counts[elem, default: 0] += 1 }
    }
}

【讨论】:

  • 谢谢!效果很好。
  • 更简单:let value = acc[key, default: 0] + 1
  • 大声笑,我知道@MartinR。这次我专注于手头的问题,没有看其余的代码。
【解决方案2】:

首先,您可以将 Element 类型限制为只能是 Hashable。

extension Array where Array.Element:Hashable {

在此之后,您可能会收到另一个错误,因为 swift 编译器有点“过度紧张”。试着给他一个提示:

typealias RT = [Array.Element: Int]

并在任何地方使用它。所以:

extension Array where Array.Element:Hashable {
    typealias RT = [Array.Element: Int]
    func histogram() -> RT {
        return self.reduce(RT()) { (acc, key) in
            let value = (acc[key] == nil) ? 1 : (acc[key]! + 1)
            return acc.dictionaryByUpdatingKey(key: key, value: value)
        }
    }
}

终于可以工作了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-02
    • 2014-02-03
    • 1970-01-01
    • 2013-06-19
    • 2014-04-26
    • 1970-01-01
    • 2013-07-09
    • 2015-02-10
    相关资源
    最近更新 更多