Массив из словарных ключей в swift


256

Попытка заполнить массив строками из ключей в словаре в swift.

var componentArray: [String]

let dict = NSDictionary(contentsOfFile: NSBundle.mainBundle().pathForResource("Components", ofType: "plist")!)
componentArray = dict.allKeys

Это возвращает ошибку: «AnyObject» не идентичен строке

Также попробовал

componentArray = dict.allKeys as String 

но получите: «String» не конвертируется в [String]

Ответы:


534

Свифт 3 и Свифт 4

componentArray = Array(dict.keys) // for Dictionary

componentArray = dict.allKeys // for NSDictionary

Интересно, что в цикле for - для имени в dict.allKeys - «имя» становится строкой и может быть напечатано и обработано иным образом.
green_knight

У dict нет метода ключей. Это экземпляр NSDictionary, а не словарь.
Womble

2
dict.map {$ 0.key}
Ниланшу Джайсвал

55

С Swift 3, Dictionaryесть keysсвойство. keysимеет следующую декларацию:

var keys: LazyMapCollection<Dictionary<Key, Value>, Key> { get }

Коллекция, содержащая только ключи словаря.

Обратите внимание , что LazyMapCollectionэто легко может быть сопоставлено с Arrayс Array«S init(_:)инициализатором.


От NSDictionaryк[String]

Следующий AppDelegateфрагмент класса iOS показывает, как получить массив строк ( [String]), используя keysсвойство из NSDictionary:

введите описание изображения здесь

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    let string = Bundle.main.path(forResource: "Components", ofType: "plist")!
    if let dict = NSDictionary(contentsOfFile: string) as? [String : Int] {
        let lazyMapCollection = dict.keys
        
        let componentArray = Array(lazyMapCollection)
        print(componentArray)
        // prints: ["Car", "Boat"]
    }
    
    return true
}

От [String: Int]к[String]

В более общем виде следующий код Playground показывает, как получить массив строк ( [String]), используя keysсвойство из словаря со строковыми ключами и целочисленными значениями ( [String: Int]):

let dictionary = ["Gabrielle": 49, "Bree": 32, "Susan": 12, "Lynette": 7]
let lazyMapCollection = dictionary.keys

let stringArray = Array(lazyMapCollection)
print(stringArray)
// prints: ["Bree", "Susan", "Lynette", "Gabrielle"]

От [Int: String]к[String]

Следующий код Playground показывает, как получить массив строк ( [String]), используя keysсвойство из словаря с целочисленными ключами и строковыми значениями ( [Int: String]):

let dictionary = [49: "Gabrielle", 32: "Bree", 12: "Susan", 7: "Lynette"]
let lazyMapCollection = dictionary.keys
    
let stringArray = Array(lazyMapCollection.map { String($0) })
// let stringArray = Array(lazyMapCollection).map { String($0) } // also works
print(stringArray)
// prints: ["32", "12", "7", "49"]

спасибо за детали В Swift 4.x тип - есть Dictionary<String, String>.Keysли у вас понимание, когда мы хотим использовать этот тип и как?
bshirley

46

Массив из словарных ключей в Swift

componentArray = [String] (dict.keys)

Я не знаю, почему люди не предпочитают сокращенный синтаксис, в то время как это намного более понятно для понимания.
Наташа

9

dict.allKeysэто не строка Это [String]именно то, о чем говорится в сообщении об ошибке (если, конечно, все ключи являются строками; это именно то, что вы утверждаете, когда говорите это).

Итак, либо начните с того, что наберите componentArrayas [AnyObject], потому что это то, как он печатается в API-интерфейсе Какао, либо, если вы разыгрываете dict.allKeys, приведите его [String], потому что это то, как вы ввели componentArray.


1
Кажется, это больше не так. В Swift 4.2 dict.keys (который заменяет .allKeys) не является [String], это [Dictionary <String, Any> .Keys] и должен быть приведен перед присвоением переменной типа [String] @santo, кажется, имеет самый простой рабочий пример того, как это сделать.
TimeSmith

5
extension Array {
    public func toDictionary<Key: Hashable>(with selectKey: (Element) -> Key) -> [Key:Element] {
        var dict = [Key:Element]()
        for element in self {
            dict[selectKey(element)] = element
        }
        return dict
    }
}

3

NSDictionary - это класс (передача по ссылке). Словарь - это структура (передача по значению ) ====== Массив из NSDictionary ======NSDictionary является типом класса Словарь - это структура ключа и значения

NSDictionary имеет allKeys, а allValues получают свойства с типом [Any] .NSDictionary имеет свойства get [Any] для allkeys и allvalues

  let objesctNSDictionary = 
    NSDictionary.init(dictionary: ["BR": "Brazil", "GH": "Ghana", "JP": "Japan"])
            let objectArrayOfAllKeys:Array = objesctNSDictionary.allKeys
            let objectArrayOfAllValues:Array = objesctNSDictionary.allValues
            print(objectArrayOfAllKeys)
            print(objectArrayOfAllValues)

====== Array From Dictionary ======

Справочник Apple по ключевым словам и значениям словаря . введите описание изображения здесь

введите описание изображения здесь

let objectDictionary:Dictionary = 
            ["BR": "Brazil", "GH": "Ghana", "JP": "Japan"]
    let objectArrayOfAllKeys:Array = Array(objectDictionary.keys)          
    let objectArrayOfAllValues:Array = Array(objectDictionary.values)
    print(objectArrayOfAllKeys)
    print(objectArrayOfAllValues)


3

Из официальной документации Array Apple :

init(_:) - Создает массив, содержащий элементы последовательности.

декларация

Array.init<S>(_ s: S) where Element == S.Element, S : Sequence

параметры

s - последовательность элементов для превращения в массив.

обсуждение

Вы можете использовать этот инициализатор для создания массива из любого другого типа, который соответствует протоколу Sequence ... Вы также можете использовать этот инициализатор для преобразования сложной последовательности или типа коллекции обратно в массив. Например, свойство keys словаря не является массивом с собственным хранилищем, это коллекция, которая отображает свои элементы из словаря только при обращении к ним, экономя время и пространство, необходимые для выделения массива. Однако если вам нужно передать эти ключи методу, который принимает массив, используйте этот инициализатор для преобразования этого списка из его типа LazyMapCollection<Dictionary<String, Int>, Int> to a simple [String].

func cacheImagesWithNames(names: [String]) {
    // custom image loading and caching
 }

let namedHues: [String: Int] = ["Vermillion": 18, "Magenta": 302,
        "Gold": 50, "Cerise": 320]
let colorNames = Array(namedHues.keys)
cacheImagesWithNames(colorNames)

print(colorNames)
// Prints "["Gold", "Cerise", "Magenta", "Vermillion"]"

2

Вы можете использовать dictionary.map следующим образом:

let myKeys: [String] = myDictionary.map{String($0.key) }

Объяснение: Карта перебирает myDictionary и принимает каждую пару ключ-значение как $ 0. Отсюда вы можете получить $ 0.key или $ 0.value. Внутри замыкающего замыкания {} вы можете преобразовать каждый элемент и вернуть этот элемент. Так как вы хотите $ 0, и вы хотите его как строку, то вы конвертируете, используя String ($ 0.key). Вы собираете преобразованные элементы в массив строк.


1

Этот ответ будет для быстрого словаря со строковыми ключами. Как этот ниже .

let dict: [String: Int] = ["hey": 1, "yo": 2, "sup": 3, "hello": 4, "whassup": 5]

Вот расширение, которое я буду использовать.

extension Dictionary {
  func allKeys() -> [String] {
    guard self.keys.first is String else {
      debugPrint("This function will not return other hashable types. (Only strings)")
      return []
    }
    return self.flatMap { (anEntry) -> String? in
                          guard let temp = anEntry.key as? String else { return nil }
                          return temp }
  }
}

И я получу все ключи позже, используя это.

let componentsArray = dict.allKeys()


-2
// Old version (for history)
let keys = dictionary.keys.map { $0 }
let keys = dictionary?.keys.map { $0 } ?? [T]()

// New more explained version for our ducks
extension Dictionary {

    var allKeys: [Dictionary.Key] {
        return self.keys.map { $0 }
    }
}

2
Привет всем! Хотя этот фрагмент кода может быть решением, включение объяснения действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете код.
Крыло
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.