У меня есть отсортированный массив
let things = [
Thing(activity: "1", name: "value1"),
Thing(activity: "1", name: "value2"),
Thing(activity: "1", name: "value3"),
Thing(activity: "2", name: "value4"),
Thing(activity: "2", name: "value5"),
Thing(activity: "3", name: "value6"),
Thing(activity: "3", name: "value7"),
Thing(activity: "1", name: "value8"),
Thing(activity: "1", name: "value9"),
Thing(activity: "1", name: "value10")
]
Я хотел бы создать массив массивов, разделенных при изменении значения активности, как показано ниже
[[Thing(activity: "1", name: "value1"),
Thing(activity: "1", name: "value2"),
Thing(activity: "1", name: "value3")],
[Thing(activity: "2", name: "value4"),
Thing(activity: "2", name: "value5")],
[Thing(activity: "3", name: "value6"),
Thing(activity: "3", name: "value7")],
[Thing(activity: "1", name: "value8"),
Thing(activity: "1", name: "value9"),
Thing(activity: "1", name: "value10")]]
2 ответа
Как уже упоминалось @matt в комментариях, вы можете использовать метод коллекции Reduce (into :) для группировки ваших элементов, проверяя, равна ли активность последнего элемента последнего массива текущей активности элемента, если это так, просто добавьте новый элемент к последнему массиву, иначе добавьте новый массив с единственным элементом к внешнему массиву:
struct Thing {
let activity, name: String
}
let things: [Thing] = [
.init(activity: "1", name: "value1"),
.init(activity: "1", name: "value2"),
.init(activity: "1", name: "value3"),
.init(activity: "2", name: "value4"),
.init(activity: "2", name: "value5"),
.init(activity: "3", name: "value6"),
.init(activity: "3", name: "value7"),
.init(activity: "1", name: "value8"),
.init(activity: "1", name: "value9"),
.init(activity: "1", name: "value10")]
let grouped: [[Thing]] = things.reduce(into: []) {
$0.last?.last?.activity == $1.activity ?
$0[$0.index(before: $0.endIndex)].append($1) :
$0.append([$1])
}
print(grouped) // "[[__lldb_expr_1.Thing(activity: "1", name: "value1"), __lldb_expr_1.Thing(activity: "1", name: "value2"), __lldb_expr_1.Thing(activity: "1", name: "value3")], [__lldb_expr_1.Thing(activity: "2", name: "value4"), __lldb_expr_1.Thing(activity: "2", name: "value5")], [__lldb_expr_1.Thing(activity: "3", name: "value6"), __lldb_expr_1.Thing(activity: "3", name: "value7")], [__lldb_expr_1.Thing(activity: "1", name: "value8"), __lldb_expr_1.Thing(activity: "1", name: "value9"), __lldb_expr_1.Thing(activity: "1", name: "value10")]]\n"
Обобщенным решением будет:
extension Sequence {
func grouped<T: Equatable>(by block: (Element) throws -> T) rethrows -> [[Element]] {
return try reduce(into: []) { result, element in
if let lastElement = result.last?.last, try block(lastElement) == block(element) {
result[result.index(before: result.endIndex)].append(element)
} else {
result.append([element])
}
}
}
}
Тогда вы сможете:
let results = things.grouped { $0.activity }
Менее элегантное (но немного более эффективное) решение будет:
extension Sequence {
func grouped<T: Equatable>(by block: (Element) throws -> T) rethrows -> [[Element]] {
var results: [[Element]] = []
var lastValue: T?
var index = results.endIndex
for element in self {
let value = try block(element)
if let lastValue = lastValue, lastValue == value {
results[index].append(element)
} else {
results.append([element])
index = results.index(before: results.endIndex)
lastValue = value
}
}
return results
}
}
Похожие вопросы
Новые вопросы
arrays
Массив - это упорядоченная линейная структура данных, состоящая из набора элементов (значений, переменных или ссылок), каждый из которых идентифицируется одним или несколькими индексами. Когда вы спрашиваете о конкретных вариантах массивов, используйте вместо них следующие связанные теги: [vector], [arraylist], [matrix]. При использовании этого тега в вопросе, относящемся к языку программирования, пометьте вопрос используемым языком программирования.