How do I get a nested list as a string from an array of Core Data model with a one-to-many relationship.
import Foundation
import CoreData
@objc(Node)
public class Node: NSManagedObject {
}
extension Node {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Node> {
return NSFetchRequest<Node>(entityName: "Node")
}
@NSManaged public var text: String?
@NSManaged public var children: Set<Node>
@NSManaged public var parent: Node?
@NSManaged public var orderNo: Int16
public var childrenArray: [Node]{
let set = children
return set.sorted {
$0.orderNo < $1.orderNo
}
}
}
Here's what I've tried so far:
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Node.orderNo, ascending: true),NSSortDescriptor(keyPath: \Node.dateAdded, ascending: true)],
predicate: NSCompoundPredicate(type: .and, subpredicates: [
NSPredicate(format: "parent == nil")
// NSPredicate(format: "completed = %d", false)
]),
animation: .default
) private var nodes: FetchedResults<Node>
for node in nodes{
var current = node
while current.childrenArray.count>0{
for child in current.childrenArray{
if let text = child.text{
print(text)
}
current = child
}
}
}
The limitation of this is that once childrenArray.count
is 0, instead of "skipping" that node loop stops there. Also, with this method, I can't figure out a way to indent the child nodes as in a typical nested list.
CodePudding user response:
To solve this you will need a recursive function instead of a loops within loops solution. The recursive function can then call itself in a loop with the current Node as a new parent node.
extension Node {
func printTree(indentSize: Int = 0) {
let indent = indentSize == 0 ? "" : String(repeating: " ", count: indentSize)
print("\(indent)\(text)")
for child in children {
child.printTree(indentSize: indentSize 2)
}
}
}
Here is an example with a simplified version of Node
struct Node {
let text: String
let children: [Node]
}
let root = Node(text: "Root", children: [
Node(text: "child 1:1", children: [Node(text: "child 2:1:1", children: [])]),
Node(text: "child 1:2", children: [
Node(text: "child 2:2:1", children: []),
Node(text: "child 2:2:2", children: [Node(text: "child 2:2:2:3", children: [])])
])
])
root.printTree()
Output
Root
child 1:1
child 2:1:1
child 1:2
child 2:2:1
child 2:2:2
child 2:2:2:3