Swift中不区分大小写的字典

问题描述 投票:6回答:4

鉴于DictionaryKey类型为String,有没有办法以不区分大小写的方式访问该值?例如:

let dict = [
    "name": "John",
    "location": "Chicago"
]

有没有办法打电话给qazxsw poi等,仍然可以获得qazxsw poi?

swift swift2
4个回答
6
投票

Swift支持多个下标,因此您可以利用它来定义不区分大小写的访问者:

dict["NAME"], dict["nAmE"]

此扩展仅限于"John",其extension Dictionary where Key : StringLiteralConvertible { subscript(ci key : Key) -> Value? { get { let searchKey = String(key).lowercaseString for k in self.keys { let lowerK = String(k).lowercaseString if searchKey == lowerK { return self[k] } } return nil } } } // Usage: let dict = [ "name": "John", "location": "Chicago", ] print(dict[ci: "NAME"]) // John print(dict[ci: "lOcAtIoN"]) // Chicago 的类型为Dictionary(因为小写与其他数据类型无关)。但是,Swift会抱怨将一般类型限制为Key。最接近String的协议是struct

请注意,如果您有两个小写形式相同的键,则无法保证您将获得哪一个:

String

6
投票

更清洁的方法,迅捷4:

StringLiteralConvertible

2
投票

现有的答案很好,但是那些策略的查找/插入的时间复杂度从O(1)到O(N)(其中N是字典中的对象数)恶化。

要保留O(1),您可能需要考虑以下方法:

let dict = [
    "name": "John",
    "NAME": "David",
]

print(dict[ci: "name"])   // no guarantee that you will get David or John.

0
投票

可以使用extension Dictionary where Key == String { subscript(caseInsensitive key: Key) -> Value? { get { if let k = keys.first(where: { $0.caseInsensitiveCompare(key) == .orderedSame }) { return self[k] } return nil } set { if let k = keys.first(where: { $0.caseInsensitiveCompare(key) == .orderedSame }) { self[k] = newValue } else { self[key] = newValue } } } } // Usage: var dict = ["name": "John"] dict[caseInsensitive: "NAME"] = "David" // overwrites "name" value print(dict[caseInsensitive: "name"]!) // outputs "David" 从映射为小写的所有键中找到第一个小写匹配,然后从此结果返回值。

/// Wrapper around String which uses case-insensitive implementations for Hashable
public struct CaseInsensitiveString: Hashable, LosslessStringConvertible, ExpressibleByStringLiteral {
    public typealias StringLiteralType = String

    private let value: String
    private let caseInsensitiveValue: String

    public init(stringLiteral: String) {
        self.value = stringLiteral
        self.caseInsensitiveValue = stringLiteral.lowercased()
    }

    public init?(_ description: String) {
        self.init(stringLiteral: description)
    }

    public var hashValue: Int {
        return self.caseInsensitiveValue.hashValue
    }

    public static func == (lhs: CaseInsensitiveString, rhs: CaseInsensitiveString) -> Bool {
        return lhs.caseInsensitiveValue == rhs.caseInsensitiveValue
    }

    public var description: String {
        return value
    }
}

var dict = [CaseInsensitiveString: String]()
dict["name"] = "John"
dict["NAME"] = "David" // overwrites "name" value
print(dict["name"]!) // outputs "David"

Collection's first(where:)是一种过滤或迭代大型集合的高效方法

参考:

  • extension Dictionary where Key == String { func valueForKeyInsensitive<T>(key: Key) -> T? { let foundKey = self.keys.first { $0.compare(key, options: .caseInsensitive) == .orderedSame } ?? key return self[foundKey] as? T } }
  • first(where:)
© www.soinside.com 2019 - 2024. All rights reserved.