#swift
#swift
Вопрос:
Например:
[Test(count: 5, name: "Ivan", innerNumber: "123123"),
Test(count: 5, name: "Ivan", innerNumber: "123123"),
Test(count: 10, name: "Miko", innerNumber: "4312432"),
Test(count: 10, name: "Miko", innerNumber: "4312432")]
Я хочу сгруппировать массив по name
полю и суммировать по count
полю
В результате я хочу получить массив в виде:
[Test(count: 10, name: "Ivan", innerNumber: "123123"),
Test(count: 20, name: "Miko", innerNumber: "4312432")]
Комментарии:
1. Используйте словарь (группировка:по:), где вы группируете по имени, затем вычисляете общее количество для каждой записи в словаре и создаете новый тест с общим и уникальным именем. Затем вам нужно решить, что делать, если внутренний номер не является уникальным для группы
2. Вы можете написать несколько примеров кода, как это выглядит. Поле внутреннего номера можно игнорировать.
3. Я дал вам идею, как это сделать, почему бы не попробовать самому?
Ответ №1:
Просто убедитесь, что ваша коллекция отсортирована по имени, и используйте reduce для накопления значения count:
let grouped: [Test] = tests.sorted(by: {$0.name < $1.name}).reduce(into: []){
if let last = $0.last, last.name == $1.name,
last.innerNumber == $1.innerNumber {
$0[$0.indices.last!] = .init(count: last.count $1.count, name: last.name, innerNumber: last.innerNumber)
} else {
$0.append($1)
}
}
Комментарии:
1. Спасибо! выглядит лаконично!
Ответ №2:
Dictionary(grouping:by:)
отлично подходит для этого:
struct Test: Hashable {
let count: Int
let name: String
let innerNumber: String // Well that's not really a number, is it 🤨
}
let input = [
Test(count: 5, name: "Ivan", innerNumber: "123123"),
Test(count: 5, name: "Ivan", innerNumber: "123123"),
Test(count: 10, name: "Miko", innerNumber: "4312432"),
Test(count: 10, name: "Miko", innerNumber: "4312432"),
]
let output = Dictionary(grouping: input, by: .name)
.map { name, tests -> Test in
let sum = tests.lazy.map(.count).reduce(0, )
// Assumes that all tests with the same name also have the same innerNumber.
// You might want to verify that with an assertion.
let innerNumber = tests.first!.innerNumber
return Test(count: sum, name: name, innerNumber: innerNumber)
}
for test in output {
print(test)
}