是否有Swift内置的默认字典,类似于Array(重复:0,计数:x)?

时间:2019-05-08 00:18:42

标签: swift

有没有一种方法可以创建默认字典来计算字符/字符串/其他内容? Python有方便的Counter()类,但是我找不到能实例化任何东西的Swift,类似于Array(repeating:0,count:x)。我知道我可以自己做。我在问Foundation是否已经有类似的东西了……因为我找不到它。谢谢!

更新 以下是最接近的两个答案: 通过@matt

let s = "abracadabra"
let letters = s.map {String($0)}
var countedLetters = [String:Int]()
letters.forEach {countedLetters[$0, default:0] += 1}
countedLetters // ["b": 2, "a": 5, "r": 2, "d": 1, "c": 1]

和其他人:

let letters: [Character] = ["a", "b", "c"]
let countedLetters: [Character: Int] = Dictionary(uniqueKeysWithValues: zip(letters, repeatElement(1, count: letters.count)))
print(countedLetters)

我只是希望在所有这些之上建立一个抽象,类似于Python的Counter()。

它显然不存在。谢天谢地扩展:)

旧示例问题

例如:

let letters = ["a", "b", "c"]
let countedLetters: [Character: Int] = Dictionary(default: 1, forKeys: letters)
print(countedLetters)
// "a": 1
// "b": 1
// "c": 1

5 个答案:

答案 0 :(得分:3)

赞:

var countedLetters = [String:Int]()
letters.forEach {countedLetters[$0, default:0] += 1}

示例:

let s = "abracadabra"
let letters = s.map {String($0)}
var countedLetters = [String:Int]()
letters.forEach {countedLetters[$0, default:0] += 1}
countedLetters // ["b": 2, "a": 5, "r": 2, "d": 1, "c": 1]

答案 1 :(得分:3)

您可以使用Dictionary init(uniqueKeysWithValues:)。这与文档中显示的示例非常相似。

let letters: [Character] = ["a", "b", "c"]
let countedLetters: [Character: Int] = Dictionary(uniqueKeysWithValues: zip(letters, Array(repeating: 1, count: letters.count)))
print(countedLetters)

输出:

  

[“ a”:1,“ b”:1,“ c”:1]

答案 2 :(得分:2)

如果您要计算字母,则不需要。您可以只使用Dictionary.subscript(_:default:)

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

print("aaabbcc".histogram())

用法上仍存在细微差异。 Python的defaultdict定义了defaultdict创建期间丢失键的默认值,而此下标要求在访问时输入默认值。它更灵活,但可能不太方便。这取决于用例。

如果此使用模式不适合您的账单,则可以创建自己的DefaultDictionary,包装字典,默认值并隐式使用Dictionary.subscript(_:default:)。这是一个粗略的开始:

public struct DefaultDictionary<K: Hashable, V> {
    public var dict = [K: V]()
    public var defaultValueProducer: (K) -> V

    public init(dict: [K: V], defaultValue: V) {
        self.init(dict: dict, defaultValueProducer: { _ in defaultValue })
    }

    public init(dict: [K: V], defaultValueProducer: @escaping (K) -> V) {
        self.dict = dict
        self.defaultValueProducer = defaultValueProducer
    }

    private func produceDefaultValue(forKey key: K) -> V {
        return self.defaultValueProducer(key)
    }

    public subscript(_ key: K) -> V {
        get { return self.dict[key, default: produceDefaultValue(forKey: key)] }
        set { self.dict[key, default: produceDefaultValue(forKey: key)] = newValue }
    }

    func reallyContains(key: K) -> Bool {
        return self.dict[key] != nil
    }
}

答案 3 :(得分:1)

正如罗伯提到的,您在可可中获得的最接近的是Objective-C类NSCountedSet:

touch /usr/local/etc/php/conf.d/extra_config.ini
echo extension_dir="/usr/lib/php/20180731/" >> /usr/local/etc/php/conf.d/extra_config.ini
echo extension=gd.so >> /usr/local/etc/php/conf.d/extra_config.ini
Running command php -m

答案 4 :(得分:1)

另外两个选项:

let results = Dictionary(grouping: s) { $0 }
    .mapValues { $0.count }

这看起来很直观。效率不是很高,但这并不重要,除非您在 Moby Dick上执行此操作。

或者:

let results = s.reduce(into: [:]) {
    $0[$1, default: 0] += 1
}

两者都很容易合而为一,但是我并不特别认为这会提高可读性。