311

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]

Kyle Goslan
  • 10,748
  • 7
  • 26
  • 41

12 Answers12

629

Swift 3 & Swift 4

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

componentArray = dict.allKeys // for NSDictionary
kurtanamo
  • 1,808
  • 22
  • 27
Andrius Steponavičius
  • 8,074
  • 3
  • 22
  • 25
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"]
Community
  • 1
  • 1
Imanou Petit
  • 89,880
  • 29
  • 256
  • 218
  • thanks for the detail. In Swift 4.x the type is `Dictionary.Keys` - do you have any insight when we'd want to use that type and how? – bshirley Feb 21 '19 at 23:47
54

Array from dictionary keys in Swift

componentArray = [String] (dict.keys)
Michael Dorner
  • 17,587
  • 13
  • 87
  • 117
Santo
  • 1,611
  • 3
  • 17
  • 37
11

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.

Meo Flute
  • 1,211
  • 11
  • 9
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.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    This seems no longer true. In Swift 4.2 dict.keys (which replaces .allKeys) is not a [String], it's a [Dictionary.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. – timeSmith Jan 16 '19 at 19:06
6

Swift 5

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

let k = dict.keys

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

This works for me.

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
    }
}
Tatsuyuki Ishi
  • 3,883
  • 3
  • 29
  • 41
Jitesh Desai
  • 59
  • 1
  • 5
5
dict.keys.sorted() 

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

Jlam
  • 1,932
  • 1
  • 21
  • 26
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"]"
Christopher Graf
  • 1,929
  • 1
  • 17
  • 34
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)
Darshan Panchal
  • 277
  • 3
  • 5
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()
jnblanchard
  • 1,182
  • 12
  • 12
-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
    Hey there! While this code snippet may be the solution, [including an explanation](https://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) 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. – Wing Apr 30 '19 at 14:50