{"id":18558738,"url":"https://github.com/dnadoba/tree","last_synced_at":"2025-04-10T01:32:58.824Z","repository":{"id":39857679,"uuid":"320036124","full_name":"dnadoba/Tree","owner":"dnadoba","description":"general tree data structure, tree diffing, NSOutlineView and SwiftUI support","archived":false,"fork":false,"pushed_at":"2021-09-04T06:07:13.000Z","size":319,"stargazers_count":36,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-24T14:44:15.927Z","etag":null,"topics":["genreal-tree","nsoutlineview","tree","tree-diffing"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dnadoba.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-12-09T17:52:18.000Z","updated_at":"2025-01-31T22:35:36.000Z","dependencies_parsed_at":"2022-08-09T15:35:26.471Z","dependency_job_id":null,"html_url":"https://github.com/dnadoba/Tree","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnadoba%2FTree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnadoba%2FTree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnadoba%2FTree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnadoba%2FTree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dnadoba","download_url":"https://codeload.github.com/dnadoba/Tree/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248140777,"owners_count":21054353,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["genreal-tree","nsoutlineview","tree","tree-diffing"],"created_at":"2024-11-06T21:40:56.248Z","updated_at":"2025-04-10T01:32:53.808Z","avatar_url":"https://github.com/dnadoba.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tree - general tree data structure, tree diffing, NSOutlineView and SwiftUI support [![Documentation](https://img.shields.io/badge/Documentation-\u003cColor\u003e.svg)](https://dnadoba.github.io/Tree/)\nThis package primarily includes a general tree data structure. \nIt also includes a tree diffing algorithm and `OutlineViewTreeDataSource` that allows to use Swift value types with `NSOutlineView` \nA demo App can be found in the `Tree macOS` folder and the `NSOutlineView` Playground with support for drag and drop, undo/redo and animations.\n\n`TreeNode` and `TreeList` can also be used as a model for `OutlineGroup` in SwiftUI applications. To see it in action, take a look at the `SwiftUI-iOS` or `SwiftUI-macOS` Playground. \n\n### `TreeNode`\n `TreeNode` is a general tree data structure implementation as a value type.\n Each `TreeNode` has a `value` and 0 or more `children`. It is actually just a struct which holds a value and an array of child nodes:\n \n ```swift\n struct TreeNode\u003cValue\u003e {\n \tvar value: Value\n \tvar children: [TreeNode\u003cValue\u003e]\n }\n ```\n With the help of `@resultBuilder` you can create a `TreeNode` like this:\n \u003e Note: `@resultBuilder` requires Swift 5.4 or higher (e.g. Xcode 12.5)\n\n```swift\nlet treeNode = TreeNode(\"root node\") {\n    \"child 1\"\n    \"child 2\"\n    TreeNode(\"child 3\") {\n        \"child of child 3\"\n    }\n    \"child 4\"\n}\nprint(treeNode)\n//  - root node\n//    - child 1\n//    - child 2\n//    - child 3\n//      - child of child 3\n//    - child 4\n```\n### `TreeList` - a list of `TreeNode`s\n `TreeList` is a list of `TreeNode`s, which enables multiple nodes to be at level 0.\n  In addition, `TreeList` conforms to `MutableCollection` and `BidirectionalCollection` which enables a ton of useful algorithms.\n\n```swift\nlet treeList = TreeList\u003cString\u003e {\n    \"root 1\"\n    \"root 2\"\n    TreeNode(\"root 3\") {\n        \"child of root 3\"\n    }\n    \"root 4\"\n}\nprint(treeList)\n//  - root 1\n//  - root 2\n//  - root 3\n//      - child of root 3\n//  - root 4\n```\n### additional methods\n `TreeNode` and `TreeList` have a similar API.\n They both support special map, compactMap and filter operations:\n \n ```swift\n extension TreeNode {\n     func mapValues\u003cNewValue\u003e(_ transform: (Value) -\u003e NewValue) -\u003e TreeNode\u003cNewValue\u003e\n     func mapValuesWithNode\u003cNewValue\u003e(_ transform: (TreeNode\u003cValue\u003e) -\u003e NewValue) -\u003e TreeNode\u003cNewValue\u003e\n     func mapValuesWithParents\u003cNewValue\u003e(_ transform: ([Value], Value) -\u003e NewValue) -\u003e TreeNode\u003cNewValue\u003e\n     func mapChildrenWithParents\u003cNewValue\u003e(_ transform: ([Value], [Value]) -\u003e NewValue) -\u003e [NewValue]\n \n     func compactMapValues\u003cNewValue\u003e(_ transform: (Value) -\u003e NewValue?) -\u003e TreeNode\u003cNewValue\u003e?\n \n     func filterValues(_ isIncluded: (Value) -\u003e Bool) -\u003e TreeNode\u003cValue\u003e\n }\n ```\n \n In addition, they support moving nodes which is useful for implementing drag and drop:\n \n ```swift\n extension TreeList where Value : Hashable {\n     /// Moves the TreeNodes at the given `sourceIndices` to `insertIndex`.\n     ///  The `sourceIndices` and `insertIndex` are both specified in the before state of the tree.\n     ///  If elements are removed before the `insertIndex`, the `insertIndex` will be adjusted.\n     ///\n     ///  The move operation will fail and return nil, if the `insertIndex` is a child of one of the moved TreeNodes.\n     /// - Parameters:\n     ///   - sourceIndices: the indices of the elements that should be moved\n     ///   - insertIndex: the insertion index to move the elements to\n     /// - Returns: A new Tree with the specified changes or nil if the the move was not possible\n     public func move(indices sourceIndices: [TreeIndex], to insertIndex: TreeIndex) -\u003e TreeList\u003cValue\u003e?\n }\n ```\n\n### `NSOutlineView`\n\u003e Note: `OutlineViewTreeDataSource` is defined in a seperate module called `TreeUI`. You need to `import TreeUI` to use it.\n\n `TreeList` and `TreeNode` were originaly created to be used as data model for NSOutlineView. Therefore, this package includes a tree diffing algorithm and `OutlineViewTreeDataSource` that allows to use Swift value types with `NSOutlineView`. Take a look at NSOutlineView Playground or the Tree macOS example Xcode project which are part of this repository.\n The diffing algorithm can also be used to efficiently send only what has changed over the network to another peer/server.\n \n\n### SwiftUI\n `TreeNode` and `TreeList` can be used with SwiftUI as well.\n\n```swift\nimport SwiftUI\nextension TreeNode {\n    var optionalChildren: [TreeNode\u003cValue\u003e]? {\n        children.isEmpty ? nil : children\n    }\n}\nstruct ContentView: View {\n    @State var tree: TreeList\u003cString\u003e\n    \n    var body: some View {\n        List(tree.nodes, id: \\.value, children: \\.optionalChildren) { node in\n            Text(node.value)\n        }\n    }\n}\n```\nFor a full example take a look into the SwiftUI-iOS or SwiftUI-macOS Playground.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdnadoba%2Ftree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdnadoba%2Ftree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdnadoba%2Ftree/lists"}