Я нашел похожий вопрос, но он не подходит к моему вопросу.
У меня есть 2 неравных словаря и я хочу их объединить в 1, думаю опишу на примере:
struct FirstModel: Codable {
var id: Int?
var date: String?
var name: String?
}
struct SecondModel: Codable {
var id: Int?
var date: String?
var age: String?
var position: String?
}
struct FinalModel: Codable {
var first:[FirstModel]?
var second: SecondModel?
}
// dict1: [date: [FirstModel]]
var dict1 = [
"2023-02-19": [FirstModel(id: 10, date: "2023-02-19", name: "Harry"), FirstModel(id: 11, date: "2023-02-19", name: "John")],
"2023-02-13": [FirstModel(id: 12, date: "2023-02-13", name: "Harry"), FirstModel(id: 11, date: "2023-02-13", name: "John")],
"2023-02-12": [FirstModel(id: 13, date: "2023-02-12", name: "Harry"), FirstModel(id: 11, date: "2023-02-12", name: "John")],
"2023-02-10": [FirstModel(id: 14, date: "2023-02-10", name: "Harry"), FirstModel(id: 11, date: "2023-02-10", name: "John")],
]
// dict1: [date: [SecondModel]]
var dict2 = [
"2023-02-19": [SecondModel(id: 10, date: "2023-02-19", age: 12, position: "A"), SecondModel(id: 15, date: "2023-02-19", age: 12, position: "A")],
"2023-02-09": [SecondModel(id: 20, date: "2023-02-09", age: 12, position: "A"), SecondModel(id: 17, date: "2023-02-09", age: 12, position: "A")],
"2023-02-10": [SecondModel(id: 14, date: "2023-02-10", age: 12, position: "A"), SecondModel(id: 16, date: "2023-02-10", age: 12, position: "A")],
"2023-02-12": [SecondModel(id: 27, date: "2023-02-12", age: 12, position: "A"), SecondModel(id: 11, date: "2023-02-12", age: 12, position: "A")],
"2023-02-08": [SecondModel(id: 22, date: "2023-02-08", age: 12, position: "A"), SecondModel(id: 11, date: "2023-02-08", age: 12, position: "A")]
]
И я хочу новый словарь, как этот
// newDict: [date: [id: [FinalModel]]]
var newDict = [
"2023-02-08": [
11: [FinalModel(first: nil, second: SecondModel(id: 11, date: "2023-02-08", age: 12, position: "A"))],
22: [FinalModel(first: nil, second: SecondModel(id: 22, date: "2023-02-08", age: 12, position: "A"))]
],
"2023-02-09": [
17: [FinalModel(first: nil, second: SecondModel(id: 17, date: "2023-02-09", age: 12, position: "A"))],
20: [FinalModel(first: nil, second: SecondModel(id: 20, date: "2023-02-09", age: 12, position: "A"))]
],
"2023-02-10": [
11: [FinalModel(first: [FirstModel(id: 11, date: "2023-02-10", name: "John")], second: nil)],
14: [FinalModel(first: [FirstModel(id: 14, date: "2023-02-10", name: "Harry")], second: SecondModel(id: 14, date: "2023-02-10", age: 12, position: "A")],
16: [FinalModel(first: nil, second: SecondModel(id: 16, date: "2023-02-10", age: 12, position: "A"))]
],
"2023-02-12": [
11: [FinalModel(first: [FirstModel(id: 11, date: "2023-02-12", name: "John")], second: SecondModel(id: 11, date: "2023-02-12", age: 12, position: "A"))],
13: [FinalModel(first: [FirstModel(id: 13, date: "2023-02-12", name: "Harry")], second: nil)],
27: [FinalModel(first: nil, second: SecondModel(id: 27, date: "2023-02-12", age: 12, position: "A"))]
],
"2023-02-13": [
11: [FinalModel(first: [FirstModel(id: 11, date: "2023-02-13", name: "John")], second: nil)],
12: [FinalModel(first: [FirstModel(id: 12, date: "2023-02-13", name: "Harry")], second: nil)]
],
"2023-02-19": [
10: [FinalModel(first: [FirstModel(id: 10, date: "2023-02-19", name: "Harry")], second: SecondModel(id: 10, date: "2023-02-19", age: 12, position: "A"))],
11: [FinalModel(first: [FirstModel(id: 11, date: "2023-02-19", name: "John")], second: nil)],
15: [FinalModel(first: nil, second: SecondModel(id: 15, date: "2023-02-19", age: 12, position: "A")]
],
]
Итак, Для каждого date существует много разных id, и каждый id может содержать много FirstModel и только SecondModel. Я столкнулся с некоторыми проблемами при сравнении и объединении их вместе, newdict это то, что я хочу отобразить.
Буду признателен за любую оказанную помощь. Спасибо!
Я думаю, что нашел решение, но производительность не так хороша.
Шаг 1: преобразовать dict1: [date: [FirstModel]] -> [date: [id: [FirstModel]]]
Шаг 2: преобразовать dict2: [date: [SecondModel]] -> [date: [id: [SecondModel]]]
Шаг 3: объедините dict1 и dict2 в: [date: FinalModel3(first: [id: [FirstModel]], second: [id: [SecondModel]])], временно названный dict3
Шаг 4: затем конвертируйте dict3 в: [date: [id: FinalModel2(first: [FirstModel], second: [SecondModel])]]
Я не совсем следую примеру. Откуда взялся id: 11 один? В любом случае, похоже, что Dictionary.merging(_:uniquingKeysWith:), вероятно, то, что вы ищете
@alexander это не то, что я ищу :(
@solitary Пример выглядит тщательно, но, к сожалению, я не могу понять, какой логики вы пытаетесь достичь. Имена структур немного общие, их так много, что трудно понять, как именно эти вещи связаны друг с другом. Не могли бы вы попробовать уточнить это?
@alexander Я пытаюсь, но это кажется довольно окольным шагом 1: я объединяю dict1 и dict 2 в [Date: FinalModel] (где и моя FirstModel, и SecondModel являются массивами). Шаг 2: Теперь я пытаюсь преобразовать этот словарь в желаемый: newDict: [date: [id: [FinalModel]]]. Я не знаю, возможно ли это на самом деле.
Вы можете иметь несколько FirstModel с одним и тем же идентификатором в один и тот же день, но можете ли вы иметь несколько SecondModel с одним и тем же идентификатором в один и тот же день?
@Larme Я не думаю, что есть много SecondModel, но это не исключает возможности
@JoakimDanielson Я хотел различать FirstModel и SecondModel, поэтому я разделил их на объекты
Можно сделать так, может быть pastebin.com/zcyWG6Ut, но некоторые моменты неясны, и я не проверял каждый случай.
Это должно помочь:
// Retrieve all dates
let allKeysDate = Set(dict1.keys).union(dict2.keys)
let output = allKeysDate.reduce(into: [String: [Int: [FinalModel]]]()) { partialOutput, currentDateKey in
let firstModels: [FirstModel]? = dict1[currentDateKey] //Get the firstModel for that date
let secondModels: [SecondModel]? = dict2[currentDateKey] //Get the SecondModel for that date
//Get all ids for that date, depending on the ids of firstModels & secondModels
let allIds: Set<Int> = Set(firstModels?.compactMap { $0.id } ?? []).union( secondModels?.compactMap { $0.id } ?? [])
//Create models
let models: [Int: [FinalModel]] = allIds.reduce(into: [Int: [FinalModel]]()) { partialModelResult, currentIdKey in
let first: [FirstModel] = firstModels?.filter { $0.id == currentIdKey } ?? [] //Get all FirstModel for that id
let second: [SecondModel]? = secondModels?.filter { $0.id == currentIdKey } //Get all SecondtModel for that id
//I supposed there can only be one SecondModel for each id (see `second?.first`), if not, you need to decide on the behavior
let finalModel = FinalModel(first: first.isEmpty ? nil : first, second: second?.first)
var currentlySaved = partialModelResult[currentIdKey, default: []]
currentlySaved.append(finalModel)
partialModelResult[currentIdKey] = currentlySaved
}
//Set the value for the currentDate
partialOutput[currentDateKey] = models
}
print(output)
Идея состоит в том, чтобы получить все даты (allKeysDate), перебрать их (с reduce(into:_)) и создать несколько FinalModel в соответствии с каждым id в этой дате.
Полный тестируемый код
Спасибо, этот ответ мне очень помог. Я немного изменил ваш код, чтобы он соответствовал моей проблеме. У меня также нет идентификаторов, поэтому я их разворачиваю
Кажется, что значение для "2023-02-10" неверно.