Есть ли встроенный Swift для по умолчанию, похожий на Array (повтор: 0, count: x)? - PullRequest
2 голосов
/ 08 мая 2019

Есть ли способ создать словарь по умолчанию для подсчета символов / строк / чего угодно? В Python есть удобный класс Counter (), но я не могу найти для Swift ничего такого, что могло бы просто создать экземпляр чего угодно, похожего на Array (повтор: 0, count: x). Я понимаю, что могу сделать свой собственный. Я спрашиваю, есть ли уже что-то подобное в Foundation ... потому что я не могу найти это. Спасибо!

Обновление Вот два ближайших ответа, из приведенных ниже: через @ матовый

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 ]

3 голосов
/ 08 мая 2019

Вы можете использовать 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]

3 голосов
/ 08 мая 2019

Как это:

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]
2 голосов
/ 08 мая 2019

Если вы пытаетесь считать буквы, вам это не нужно.Вы можете просто использовать 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())

Существует небольшая разница в использовании.defaultdict в Python определяет значение по умолчанию для отсутствующих ключей во время создания defaultdict, тогда как этот индекс запрашивает значение по умолчанию во время доступа.Это более гибкий, но может быть менее удобным.Это зависит от варианта использования.

Если этот шаблон использования не соответствует вашему счету, вы можете создать свой собственный DefaultDictionary, добавив в него dict, значение по умолчанию и неявно используя 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
    }
}
1 голос
/ 08 мая 2019

Еще два варианта:

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

Это выглядит красиво и интуитивно Не очень эффективно, но это не критично, если вы не делаете это на Moby Dick.

Или:

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

Оба легко сворачиваются в одну строку, но я не особо думаю, что это улучшает читабельность.

1 голос
/ 08 мая 2019

Как упоминает Роб, ближе всего к какао вы получите класс Objective-C NSCountingSet:

//Turn a string into an array of characters
let string = "aabcccdeeeef"
let array = string.map {String($0)}

//Turn the array into a counted set.
let counted = NSCountedSet(array: array)

//print the entries in the counted set. Note that sets don't preserve order
counted.forEach{ print($0, ":", counted.count(for:$0)) }

//Or if you want to use a counted set to build a dictionary of counts:
var result = [String: Int]()
array.forEach { result[$0] = counted.count(for: $0) }
print(result)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...