Swift - Как обновить объект в многомерном каталоге

Я хочу иметь возможность находить и обновлять пользовательский объект в массиве этих объектов. Проблема заключается в том, что пользовательские объекты также могут быть дочерними объектами.

Пользовательский объект выглядит следующим образом:

class CustomObject: NSObject {
    var id: String?
    var title: String?
    var childObjects: [CustomObject]?
}

Я хотел бы иметь возможность создать функцию, которая перезаписывает пользовательский объект с помощью fx определенного идентификатора, например:

 var allCustomObjects: [CustomObject]?
    
 func updateCustomObject(withId id: String, newCustomObject: CustomObject) {
        
     var updatedAllCustomObjects = allCustomObjects
        
     // ...
     // find and update the specific custom object with the id
     // ...
        
     allCustomObjects = updatedAllCustomObjects
 }

Я понимаю, что это должно быть довольно нормальной проблемой в отношении многомерных массивов/каталогов как в Swift, так и в других языках. Пожалуйста, дайте мне знать, какая обычная практика используется для этого вопроса.

Я предполагаю, что идентификаторы уникальны во всем дереве CustomObjects? Для каждого заданного идентификатора где-то в дереве есть ровно один CustomObject с этим идентификатором? (В отличие от уникального только в пределах братьев и сестер объекта)

Sweeper 18.03.2022 14:51

Я думаю, что более быстрый, как и, вероятно, более простой способ реализовать такой алгоритм — это добавить рекурсивный метод, такой как update(at id: String), который мог бы возвращать логическое значение (это сработало?) или CustomObject? (либо один был затронут или нет). С этим вы начинаете рассматривать CustomObject как дерево, которое, кажется, соответствует вашему варианту использования. Я, вероятно, не могу привести хороший пример, так как я не практиковал Swift в течение многих лет, но просмотр BTree может быть хорошим началом en.wikipedia.org/wiki/B-дерево

Zyigh 18.03.2022 14:52

@Sweeper, в этом примере идентификаторы всегда уникальны, да.

Simon Degn 18.03.2022 15:04

@Zyigh Понятно. Затем эта функция будет содержать цикл для вызова той же функции дочерних объектов и углубления в дерево?

Simon Degn 18.03.2022 15:05

Все ли дочерние объекты также находятся в allCustomObjects?

Willeke 19.03.2022 00:56
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
2
5
38
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как и в большинстве случаев, связанных с деревьями, рекурсия поможет. Вы можете добавить дополнительный параметр, который указывает, какой массив CustomObject вы просматриваете в данный момент, и возвращает Bool, указывающий, найден ли идентификатор, для целей короткого замыкания.

@discardableResult
func updateCustomObject(withId id: String, in objectsOrNil: inout [CustomObject]?, newCustomObject: CustomObject) -> Bool {
    guard let objects = objectsOrNil else { return false }
    if let index = objects.firstIndex(where: { $0.id == id }) {
        // base case: if we can find the ID directly in the array passed in
        objectsOrNil?[index] = newCustomObject
        return true
    } else { 
        // recursive case: we need to do the same thing for the children of
        // each of the objects in the array
        for obj in objects {
            // if an update is successful, we can end the loop there!
            if updateCustomObject(withId: id, in: &obj.childObjects, newCustomObject: newCustomObject) {
                return true
            }
        }
        return false
        // technically I think you can also replace the loop with a call to "contains":
        // return objects.contains(where: { 
        //     updateCustomObject(withId: id, in: &$0.childObjects, newCustomObject: newCustomObject) 
        //  })
        // but I don't like doing that because updateCustomObject has side effects
    }
}

Вы бы назвали это так, с параметром in: равным allCustomObjects.

updateCustomObject(withId: "...", in: &allCustomObjects, newCustomObject: ...)

Другие вопросы по теме