Home > Net >  Search full path for a node
Search full path for a node

Time:09-20

Lets say I have an array of Tags, where tags are:

final class Tag {
  let title: String
  let tags: [Tag] // A tag can have 'n' children tags.
}

let myTags = [Tags]() // Filled with data

Given a Tag, I want to to get in order the full path of its parents. So for example, tag A142, should return [A, A1, A14]. (Invented titles, they don't store this data, but it will be helpful to visualize what I'm searching for)

Tried different versions but I'm unable to get recursion going on:

func searchPath(for tag: Tag, in data: [Tag], path: [Tag]) -> [Tag]? {
    for child in data {
        print(child.title)
        if child.tags.isEmpty && child == tag {
            return path
        } else if !child.tags.isEmpty {
            return searchPath(for: tag, in: child.tags, path: path   [child])
        } else {
        }
    }
    return []
}

A more detailed example would be:

private let mock: [Tag] = {
    [
        .init(title: "Car", tags: [
            .init(title: "Porsche", tags: []),
            .init(title: "BMW", tags: [])
        ]),
        .init(title: "Flight", tags: [
            .init(title: "A1", tags: [
                .init(title: "A11", tags: []),
                .init(title: "A12", tags: [
                    .init(title: "A121", tags: []),
                    .init(title: "A122", tags: [])
                ])
            ]),
            .init(title: "A2", tags: [])
        ])
    ]
}()

So searching for the tag A122 in "mock", should return tags for "Fligh", "A1, "A12".

CodePudding user response:

This solution consists of two functions because I was originally working with a tree solution before I understood that the input was an array.

First the main one

public func searchPath(for tag: Tag, in data: [Tag]) -> [Tag] {
    var result = [Tag]()
    for item in data {
        searchPath(for: tag, in: item, path: &result)
        if result.isEmpty == false { break}
    }
    return result
}

and then the recursive one that does the actual searching and builds up the path

private func searchPath(for tag: Tag, in parent: Tag, path: inout [Tag]) {
    guard parent.tags.isEmpty == false else { return }

    path.append(parent) // always add the parent

    if parent.tags.contains(tag) { return } // we have a match, current path is the end result
    for child in parent.tags where child.tags.isEmpty == false {
        searchPath(for: tag, in: child, path: &path)
        if path.isEmpty == false { return } // we have a path
    }

    path = [] //No match if we get here, clear the path.
}

This solution require that Tag conforms to Equatable

  • Related