Stuart
Stuart

Reputation: 37053

Swift Dictionary: Get values as array

I have a dictionary containing UIColor objects hashed by an enum value, ColorScheme:

var colorsForColorScheme: [ColorScheme : UIColor] = ...

I would like to be able to extract an array of all the colors (the values) contained by this dictionary. I thought I could use the values property, as is used when iterating over dictionary values (for value in dictionary.values {...}), but this returns an error:

let colors: [UIColor] = colorsForColorSchemes.values
                        ~~~~~~~~~~~~~~~~~~~~~^~~~~~~
'LazyBidrectionalCollection<MapCollectionView<Dictionary<ColorScheme, UIColor>, UIColor>>' is not convertible to 'UIColor'

It seems that rather than returning an Array of values, the values method returns a more abstract collection type. Is there a way to get an Array containing the dictionary's values without extracting them in a for-in loop?

Upvotes: 208

Views: 141495

Answers (7)

krlbsk
krlbsk

Reputation: 1061

You can also use flatMap:

let colors = colorsForColorScheme.values.flatMap { $0 }

Upvotes: 2

Natasha
Natasha

Reputation: 6893

Firstly, from the following statement, it seems that your variable(dictionary) name is colorsForColorScheme

var colorsForColorScheme: [ColorScheme : UIColor] = ... 

while you are trying to get the values from colorsForColorSchemes dictionary when you did-

let colors: [UIColor] = colorsForColorSchemes.values

which should give you a compile time error. Anyways I am assuming that you had a typo, and you dictionary's name is colorsForColorSchemes. So, here is the solution-

As mentioned earlier, because of the type inference property in swift, your code can infer that the returned type from the .values function is returning an array of UIColor. However, Swift wants to be type-safe, so when you store the values in the colors array, you need to explicitly define that. For swift 5 and above, now you could just do following-

let colors = [UIColor](colorsForColorSchemes.values)

Upvotes: 7

pjuzeliunas
pjuzeliunas

Reputation: 1656

You can map dictionary to an array of values:

let colors = colorsForColorScheme.map { $0.1 }

Closure takes a key-value tuple from dictionary and returns just a value. So, map function produces an array of values.

More readable version of the same code:

let colors = colorsForColorScheme.map { (scheme, color) in
    return color
}

UPDATE

From Xcode 9.0, dictionary values can be accessed using values property, which conforms to Collection protocol:

let colors = colorsForColorScheme.values

Typically you just want it as an array:

let colors = Array(dict.values)

and that's it.

Upvotes: 92

andrewlundy_
andrewlundy_

Reputation: 1143

I've found this to be the most useful in Swift 5:

colorsForColorSchemes.allValues

See docs - https://developer.apple.com/documentation/foundation/nsdictionary/1408915-allvalues

Upvotes: 0

Vishal kundaliya
Vishal kundaliya

Reputation: 111

Use colorsForColorScheme.map({$0.value})

Upvotes: 11

GSerjo
GSerjo

Reputation: 4778

you can create an extension on LazyMapCollection

public extension LazyMapCollection  {

    func toArray() -> [Element]{
        return Array(self)
    }
}

colorsForColorSchemes.values.toArray() or colorsForColorSchemes.keys.toArray()

Upvotes: 10

Stuart
Stuart

Reputation: 37053

As of Swift 2.0, Dictionary’s values property now returns a LazyMapCollection instead of a LazyBidirectionalCollection. The Array type knows how to initialise itself using this abstract collection type:

let colors = Array(colorsForColorSchemes.values)

Swift's type inference already knows that these values are UIColor objects, so no type casting is required, which is nice!

Upvotes: 354

Related Questions