2017-02-04 4 views
10

Я пишу расширение, чтобы соединить значения словаря между FirebaseDatabase и Eureka.Array.map() производит '[T]', а не ожидаемый тип контекстуального результата '[String: Any?]'

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

Но я брошу эту ошибку, когда я пытаюсь построить:

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

+0

@ Xcoder123 Я думаю, что мой вопрос имеет больше общего с моим пониманием Свифта 'Array.map()', а не сама Эврика –

+0

[Это] (http://stackoverflow.com/a/44112062/3411787) помог мне. –

ответ

4

Ваша проблема заключается в том, что map всегда возвращает Array, даже если применяется на Dictionary. Ваше сообщение об ошибке в основном означает, что вы объявили свой метод как возвращающий Dicitonary, но в заявлении внутри возвращается Array ([T] - означает массив с объектами тип T). В вашем случае массив, возвращаемый map, будет содержать кортежей (подробнее о них here). В этом случае он выглядит как пара значений ключа, но не эквивалентен паре ключ-значение внутри Словаря. В основном, кортежи позволяют вам возвращать более одного значения/объекта из метода. Вы можете думать о них как о анонимных структур.

На мой взгляд, нет необходимости использовать map, чтобы выполнить то, что вам нужно - решение, предлагаемое г-ном Xcoder, - это путь.

+1

Отмечено как правильный ответ для ясности в объяснении. Короче: массив кортежей ≠ словарь ... '[(String, Any?)] ≠ [String: Any?]'. Спасибо! –

4

Я не мог понять, как исправить эту ошибку, ни я не удался достичь желаемого результата с расширение или map(), но у меня есть альтернативное решение проблемы, используя функцию :

Декларирование Словарь:

var date = NSDate() 
var swiftDict:[String : Any?] = ["1": date, "2": "two", "3": 15, "4": true] 

Функция:

func firebaseFriendlyDictionary(_ dict: [String : Any?]) -> [String : Any?]{ 
    var Dict = dict 
    for (key, value) in dict 
    { 
     if (value is NSDate){ 
      Dict[key] = (value as! NSDate).timeIntervalSince1970 
     } 
    } 
    return Dict 
} 

Использование:

swiftDict = firebaseFriendlyDictionary(swiftDict) 

Тестирование:

Ass uming, что у нас есть дата 2017-02-04 16:42:46 +0000, выход 1486226566.2349629, что является правильным.

Почему бы не сопоставить словарь? Как Losiowaty отметил в своем замечательном ответе, map всегда возвращает Array, в этом случае Array из Tuples ([T]). На мой взгляд, в этом контексте функция карты не нужна, плюс ей требуется больше кода для выполнения.

Надеюсь, это поможет!

+0

Я представил ответ с объяснением ошибки. Я собирался опубликовать такой же подход, чтобы выполнить случай использования OPs;) – Losiowaty

+0

@ Losiowaty, так как вы думаете, что это хороший подход? –

+0

Да, я бы сделал это так, как вы это сделали. – Losiowaty

5

Если вы действительно хотите использовать что-то функциональное, например map, метод, который вы на самом деле хотите, это reduce.

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

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

Итак, вот наш тестовый словарь:

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

Теперь мы готовы к применению reduce. Он передает два параметра в свою функцию. Первый - это «аккумулятор», в котором мы продолжаем формировать конечный результат, который в этом случае является другим словарем. Второй элемент исходного словаря представлен в виде кортежа пар ключ-значение называется key и value:

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

И когда мы исследуем d2, мы видим, что мы получили правильный ответ:

d2 // ["3": {some 15}, "2": {some "two"}, "1": {some 1486228695.557882}, "4": {some true}] 
+0

Уменьшение похоже на путь. Я вместо этого ответил на [Лосиоватый ответ] (http://stackoverflow.com/a/42042946/4773291), потому что объясняет эту ошибку. Спасибо! –

+0

По какой-то странной причине «initialResult» из моего сокращения является константой let ... –

+2

Я не знаю, что вы делаете, но то, что я показал вам, работает. Обратите внимание, что в первой строке моей функции 'reduce' я присваиваю' dict' в 'var'; это то, о чем вы говорите? Эта линия имеет решающее значение. (Ну, это очень важно, все это висит вместе.) – matt

Смежные вопросы