321

Trying to fill an array with strings from the keys in a dictionary in swift.

var componentArray: [String]

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

This returns an error of: 'AnyObject' not identical to string

Also tried

componentArray = dict.allKeys as String 

but get: 'String' is not convertible to [String]

0

12 Answers 12

638

Swift 3 & Swift 4

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

componentArray = dict.allKeys // for NSDictionary
Sign up to request clarification or add additional context in comments.

4 Comments

Interestingly, in a for loop - for name in dict.allKeys - 'name' becomes a string and can be printed and otherwise processed.
dict does not have a keys method. It's an instance of NSDictionary, not a Dictionary.
dict.map { $0.key }
Note that this method doesn't preserve the keys' order
58

Array from dictionary keys in Swift

componentArray = [String] (dict.keys)

3 Comments

I don't know, why people don't prefer the shorthand syntax while it is much more clear to understand.
I can't tell you how much handwringing you solved for me. thanks!!!
This should really be the solution, super simple, hardly anything to type and makes the most sense.
58

With Swift 3, Dictionary has a keys property. keys has the following declaration:

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

A collection containing just the keys of the dictionary.

Note that LazyMapCollection that can easily be mapped to an Array with Array's init(_:) initializer.


From NSDictionary to [String]

The following iOS AppDelegate class snippet shows how to get an array of strings ([String]) using keys property from a NSDictionary:

enter image description here

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
}

From [String: Int] to [String]

In a more general way, the following Playground code shows how to get an array of strings ([String]) using keys property from a dictionary with string keys and integer values ([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"]

From [Int: String] to [String]

The following Playground code shows how to get an array of strings ([String]) using keys property from a dictionary with integer keys and string values ([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"]

1 Comment

thanks for the detail. In Swift 4.x the type is Dictionary<String, String>.Keys - do you have any insight when we'd want to use that type and how?
14

You can use dictionary.map like this:

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

The explanation: Map iterates through the myDictionary and accepts each key and value pair as $0. From here you can get $0.key or $0.value. Inside the trailing closure {}, you can transform each element and return that element. Since you want $0 and you want it as a string then you convert using String($0.key). You collect the transformed elements to an array of strings.

Comments

9

dict.allKeys is not a String. It is a [String], exactly as the error message tells you (assuming, of course, that the keys are all strings; this is exactly what you are asserting when you say that).

So, either start by typing componentArray as [AnyObject], because that is how it is typed in the Cocoa API, or else, if you cast dict.allKeys, cast it to [String], because that is how you have typed componentArray.

1 Comment

This seems no longer true. In Swift 4.2 dict.keys (which replaces .allKeys) is not a [String], it's a [Dictionary<String, Any>.Keys] and must be cast before assigning to a variable of type [String] @santo seems to have the simplest working example of how to do that.
6

Swift 5

var dict = ["key1":"Value1", "key2":"Value2"]

let k = dict.keys

var a: [String]()
a.append(contentsOf: k)

This works for me.

Comments

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
    }
}

Comments

5
dict.keys.sorted() 

that gives [String] https://developer.apple.com/documentation/swift/array/2945003-sorted

Comments

5

From the official Array Apple documentation:

init(_:) - Creates an array containing the elements of a sequence.

Declaration

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

Parameters

s - The sequence of elements to turn into an array.

Discussion

You can use this initializer to create an array from any other type that conforms to the Sequence protocol...You can also use this initializer to convert a complex sequence or collection type back to an array. For example, the keys property of a dictionary isn’t an array with its own storage, it’s a collection that maps its elements from the dictionary only when they’re accessed, saving the time and space needed to allocate an array. If you need to pass those keys to a method that takes an array, however, use this initializer to convert that list from its type of 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"]"

Comments

3

NSDictionary is Class(pass by reference) NSDictionary is class type Dictionary is Structure(pass by value) Dictionary is structure of key and value ====== Array from NSDictionary ======

NSDictionary has allKeys and allValues get properties with type [Any].NSDictionary has get [Any] properties for allkeys and 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 reference for Dictionary's keys and values properties. enter image description here

enter image description here

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)

Comments

0

This answer will be for swift dictionary w/ String keys. Like this one below.

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

Here's the extension I'll use.

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 }
  }
}

And I'll get all the keys later using this.

let componentsArray = dict.allKeys()

Comments

-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 }
    }
}

1 Comment

Hey there! While this code snippet may be the solution, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.