По сути, вы пытаетесь достичь соответствия между одним набором значений и другим.Для этого в словаре есть функция Dictionary.mapValues(_:)
, специально предназначенная только для отображения значений (удерживая их под теми же клавишами).
let appRatings = [
"Calendar Pro": [1, 5, 5, 4, 2, 1, 5, 4],
"The Messenger": [5, 4, 2, 5, 4, 1, 1, 2],
"Socialise": [2, 1, 2, 2, 1, 2, 4, 2]
]
let avgAppRatings = appRatings.mapValues { allRatings in
return computeAverage(of: allRatings) // Dummy function we'll implement later
}
Итак, теперь нужно выяснить, какусреднить все числа в массиве.К счастью, это очень просто:
Нам нужно сложить все рейтинги
Мы можем легко достичь этого с помощью выражения reduce
.Мы уменьшим все числа, просто добавив их в аккумулятор, который будет начинаться с 0
allRatings.reduce(0, { accumulator, rating in accumulator + rate })
Отсюда мы можем заметить, что замыкание { accumulator, rating in accumulator + rate }
имеет тип (Int, Int) -> Int
и просто добавляетчисла вместе.Ну, эй, это именно то, что делает +
!Мы можем просто использовать его напрямую:
allRatings.reduce(0, +)
Нам нужно разделить рейтинги на количество рейтингов
- Естьлови здесь.Чтобы среднее значение имело какой-либо смысл, оно не может быть усечено до простого
Int.
. Поэтому нам необходимо сначала преобразовать сумму и число в Double
.
Вам нужно защититься от пустых массивов, количество которых будет равно 0, в результате чего Double.infinity
.
Собрав все это вместе, мы получим:
let appRatings = [
"Calendar Pro": [1, 5, 5, 4, 2, 1, 5, 4],
"The Messenger": [5, 4, 2, 5, 4, 1, 1, 2],
"Socialise": [2, 1, 2, 2, 1, 2, 4, 2]
]
let avgAppRatings = appRatings.mapValues { allRatings in
if allRatings.isEmpty { return nil }
return Double(allRatings.reduce(0, +)) / Double(allRatings.count)
}
Добавьте немного приятной логики печати:
extension Dictionary {
var toDictionaryLiteralString: String {
return """
[
\t\(self.map { k, v in "\(k): \(v)" }.joined(separator: "\n\t"))
]
"""
}
}
... и boom:
print(avgAppRatings.toDictionaryLiteralString)
/* prints:
[
Socialise: 2.0
The Messenger: 3.0
Calendar Pro: 3.375
]
*/
Комментарии к вашей попытке
У вас есть несколько вопросовпочему ваша попытка не сработала:
func calculate( appName: String, ratings : [Int]) -> (String: Int ) {
var avg = ratings.reduce(0,$0+$1)/ratings.count
return appName: sum/avg
}
$0+$1
не в закрытии ({ }
), как должно быть. appName: sum/avg
недопустимо Swift. - Переменная
sum
не существует. avg
является переменной var
, даже если она никогда не изменялась.Это должна быть let
константа. - Вы делаете целочисленное деление, которое не поддерживает десятичные дроби.Сначала вам нужно будет преобразовать сумму и считать в тип с плавающей запятой, например
Double
.
Фиксированная версия может выглядеть следующим образом:
func calculateAverage(of numbers: [Int]) -> Double {
let sum = Double(ratings.reduce(0, +))
let count = Double(numbers.count)
return sum / count
}
.функция, которая обрабатывает весь ваш словарь, не отвечая моим решениям, описанным выше, вы можете написать такую функцию:
func calculateAveragesRatings(of appRatings: [String: [Int]]) -> [String: Double?] {
return appRatings.mapValues { allRatings in
if allRatings.isEmpty { return nil }
return Double(allRatings.reduce(0, +)) / Double(allRatings.count)
}
}