Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array.map() produces '[T]', not the expected contextual result type '[String: Any?]'

I'm writing an extension to bridge the dictionary values between FirebaseDatabase and Eureka.

private extension Dictionary {
    func firebaseFriendlyDictionary() -> [String: Any?] {
        return self.map({ (key: String, value: Any?) -> (String, Any?) in
            if value is NSDate {
                return (key, (value as! NSDate).timeIntervalSince1970)
            }
            return (key, value)
        })
    }
}

But I get thrown this error when I try to build:

map produces '[T]', not the expected contextual result type '[String: Any?]'

like image 350
Liau Jian Jie Avatar asked Feb 04 '17 08:02

Liau Jian Jie


2 Answers

Your problem lies with the fact, that map always returns an Array, even when applied on a Dictionary. Your error message basically means, that you declared your method as returning a Dicitonary, but the statement inside returns an Array ([T] - means an Array with objects of some type T). In your case, the array returned by map will contain tuples (more about them here). In this case it looks like a key value pair, but its not equivalent to a key-value pair inside a Dictionary. Basically, tuples enable you to return more than one value/object from method. You can think of them as of anonymous structures.

In my opinion, there is no need to use a map to accomplish what you need - the solution provided by Mr. Xcoder is the way to go.

like image 137
Losiowaty Avatar answered Sep 24 '22 02:09

Losiowaty


If you really want to use something functional like map, the method you actually want is reduce.

I'll demonstrate. To make things as clear as possible, I think it will help if we separate out the transformation to which your values are being subjected into a function of its own:

func dateToSeconds(_ thing:Any?) -> Any? {
    guard let date = thing as? Date else {return thing}
    return date.timeIntervalSince1970
}

Okay, so here's our test dictionary:

let d1 : [String:Any?] = ["1":Date(), "2":"two", "3":15, "4":true]

Now we're ready to apply reduce. It passes two parameters into its function. The first is the "accumulator" where we keep building up the ultimate result, which in this case is another dictionary. The second is an element of the original dictionary, represented as a tuple of key-value pairs called key and value:

let d2 = d1.reduce([String:Any?]()) { (dict, tuple) in
    var dict = dict
    dict[tuple.key] = dateToSeconds(tuple.value)
    return dict
}

And when we examine d2, we see that we have got the right answer:

d2 // ["3": {some 15}, "2": {some "two"}, "1": {some 1486228695.557882}, "4": {some true}]
like image 44
matt Avatar answered Sep 25 '22 02:09

matt