Home > front end >  How to recursively create a Modal with an array of data in Swift
How to recursively create a Modal with an array of data in Swift

Time:03-20

I need to recursively add these comments in the correct order.

Currently i get an array of comments that are unsorted. These comments can be the top level or can be a child of the top level.

I was using this recursive method to add them but i can’t seem to get it right.

The result should be an array of CommentModal’s [CommentModal]

For reference: The postID is the topLevel comment that the child belongs to. Every child comment will have a postID so that they know where they belong to. If the child has a child, the top level child’s commentID will be the child’s postID.

Data and Data Models

struct Comment {
    var postID: String
    var commentID: String
    var date: Double
}

class CommentModal {
    var mainComment: Comment
    var childComment: [CommentModal] = []
    
    init(mainComment: Comment) {
        self.mainComment = mainComment
    }
}

let data: [Comment] = [
    Comment(postID: "RootPostID", commentID: "116", date: 1),
    Comment(postID: "RootPostID", commentID: "117", date: 2),
    Comment(postID: "RootPostID", commentID: "118", date: 3),
    Comment(postID: "116",      commentID: "216", date: 4),
    Comment(postID: "117",      commentID: "217", date: 5),
    Comment(postID: "118",      commentID: "218", date: 6),
    Comment(postID: "216",      commentID: "316", date: 7),
    Comment(postID: "216",      commentID: "317", date: 8),
]

Initialized

private func index(comments: [Comment]) {
        discardableCachedComments = comments
        commentModalArray = addChildren(from: comments)
    }

    private func addChildren(from comments: [Comment]) -> [CommentModal] {
        var result: [CommentModal] = []
        
        for comment in comments {
            let children = discardableCachedComments.filter { $0.postID == comment.commentID }
            discardableCachedComments.removeAll { $0.postID == comment.commentID }
            
            let commentModal = CommentModal(mainComment: comment)
            
            if children.count >= 1 {
                commentModal.childComment = addChildren(from: children)
            }
            discardableCachedComments.removeAll { $0.commentID == comment.commentID }
            result.append(commentModal)
        }
        
        return result
    }

Desired Output

Using the data above i want to see the result be:

An array of 3 Top Level CommentModals. Each of those Top Level CommentModals will have a childComment which is an array of CommentModal. For one of those childComment we will also see it have two values in childComment.

If you see the data you will see how the postID and commentID are assembled so that they are added correctly in its respective modal.

CodePudding user response:

I've changed a couple of names to make things semantically a little easier to understand, but this should show the gist of it. I've also changed CommentModal into a struct, since that made initialization easier, but you could change it back.

This should be copy/pastable into a Playground:

struct Comment : Codable {
    var parentID: String
    var id: String
    var date: Double
}

struct CommentModel : Codable {
    var comment: Comment
    var children: [CommentModel] = []
}

let data: [Comment] = [
    Comment(parentID: "RootPostID", id: "116", date: 1),
    Comment(parentID: "RootPostID", id: "117", date: 2),
    Comment(parentID: "RootPostID", id: "118", date: 3),
    Comment(parentID: "116",      id: "216", date: 4),
    Comment(parentID: "117",      id: "217", date: 5),
    Comment(parentID: "118",      id: "218", date: 6),
    Comment(parentID: "216",      id: "316", date: 7),
    Comment(parentID: "216",      id: "317", date: 8),
]

func createCommentModels(rootKey: String, input: [Comment]) -> [CommentModel] {
    return input
        .filter { $0.parentID == rootKey }
        .map { comment in
            return CommentModel(comment: comment,
                                children: createCommentModels(rootKey: comment.id,
                                                              input: input
                                                              ))
        }
}

func printModal(_ input: CommentModel, indent: Int = 0) {
    let indentChars = Array(repeating: " ", count: indent).joined(separator: "")
    print("\(indentChars)", input.comment.id)
    if !input.children.isEmpty {
        print("\(indentChars) - Children:")
        input.children.forEach { printModal($0, indent: indent   4)}
    }
}

let result = createCommentModels(rootKey: "RootPostID", input: data)

result.forEach {
    printModal($0)
}

Which yields:

116
 - Children:
     216
     - Children:
         316
         317
 117
 - Children:
     217
 118
 - Children:
     218
  • Related