kotlin-tree ?

Kotlin Declarative APIs for Multi-way Tree Data.

Easy to convert trees to other tree models, Path Enumeration Models and Adjacency Models, etc.

Installation

Gradle

implementation("io.github.yuitosato:kotlin-tree:1.1.0")

Maven

<dependency>
    <groupId>io.github.yuitosato</groupId>
    <artifactId>kotlin-tree</artifactId>
    <version>1.1.0</version>
</dependency>

Definition

The base class TreeNode is defined as follows.

TreeNode has the value property, which is the content of the node, and the children property, which is the node’s child nodes.

class TreeNode<T> private constructor(
    val value: T,
    val children: MutableList<TreeNode<T>>
)

Quick Start

You can create a tree node instance and operate the contents of nodes easily and simply.

val treeNode: TreeNode<Int> = nodeOf(
    1,
    mutableListOf(
        nodeOf(
            11,
            mutableList(
                leafOf(111),
                leafOf(112)
            )
        ),
        leafOf(12)
    )
)
// 1
// ├── 11
// │   ├── 111
// │   └── 112
// └── 12

treeNode.map { ele -> ele * 2 }
// 2
// ├── 22
// │   ├── 222
// │   └── 224
// └── 24

Examples

Tree Operations

kotlin-tree provides APIs that operates the contents of nodes like Kotlin Collection APIs such as map, filter, etc. Also, kotlin-tree provides APIs that operates the nodes themselves. (It means lambda blocks receive TreeNode instances, not the contents of nodes T.) These methods are named xxxNode, mapNode, filterNode, etc.

val treeNode: TreeNode<Int> = nodeOf(
    1,
    mutableListOf(
        nodeOf(
            11,
            mutableList(
                leafOf(111),
                leafOf(112)
            )
        ),
        leafOf(12)
    )
)
// 1
// ├── 11
// │   ├── 111
// │   └── 112
// └── 12

treeNode.map { ele -> ele * 2 }
treeNode.mapNode { node -> node.value * 2 }
// 2
// ├── 22
// │   ├── 222
// │   └── 224
// └── 24

treeNode.filter { ele -> ele % 2 != 0 }
treeNode.filterNode { node -> node.value % 2 != 0 }
// 1
// └── 11
//     └── 111

treeNode.find { ele -> ele > 10 }
treeNode.findNode { node -> node.value > 10 }
// [
//   11
//   ├── 111,
//   └── 112,
//   111,
//   112,
//   12
// ]

treeNode.forEach { ele -> println(ele) }
treeNode.forEachNode { node -> println(node.value) }
// => 1
// => 11
// => 111
// => 112
// => 12

treeNode.fold(0) { (acc, ele) -> acc + ele }
treeNode.foldNode(0) { (acc, node) -> node.value + ele }
// (1 + 11 + 111 + 112 + 12)

treeNode.withIndices()
// ([], 1)
// ├── ([0], 11)
// │   ├── ([0, 0], 111)
// │   └── ([0, 1], 112)
// └── ([1], 12)

treeNode.getOrElse(listOf(0, 1))
// => leafOf(112)

Adjacency Models -> Trees Conversions

val adjacencyList = AdjacencyList.of(
    getSelfNodeId = { it },
    list = listOf(
        null to 1,
        1 to 11,
        11 to 111,
        1 to 12,
        null to 2,
        2 to 21,
        3 to 31 // the parentNodeId is not found
    )
)
val (treeNodes, parentNodeNotFoundList) = adjacencyList.toTreeNode()
// treeNodes
// 1
// ├── 11
// │   ├── 111
// │   └── 112
// └── 12
// 2
// └── 21
// parentNodeNotFoundList
// (parentNodeId: 3, selfNodeId: 31)

Trees -> Adjacency Models Conversions

val treeNode = nodeOf(
    1,
    mutableListOf(
        nodeOf(
            11,
            mutableList(
                leafOf(111),
                leafOf(112)
            )
        ),
        leafOf(12)
    )
)
val adjacencyList = AdjacencyList.fromTreeNode(
    treeNode
)
// (parentNodeId, selfNodeID)
// (null, 1)
// (1, 11)
// (11, 111)
// (1, 12)

PathEnumeration Models -> Trees Conversions

val pathEnumerationList = PathEnumerationList.of(
    listOf(1) to 1,
    listOf(1, 11) to 11,
    listOf(1, 11, 111) to 111,
    listOf(1, 12) to 12,
    listOf(2) to 2,
    listOf(2, 21) to 21,
    listOf(3, 31) to 31, // the path is not found
)
val (treeNodes, parentNodeNotFoundList) =
    pathEnumerationList.toTreeNode()
// treeNodes
// 1
// ├── 11
// │   ├── 111
// │   └── 112
// └── 12
// 2
// └── 21
// parentNodeNotFoundList
// (path: 3/31, value: 31)

Trees -> PathEnumeration Models Conversions

val treeNode = nodeOf(
    1,
    mutableListOf(
        nodeOf(
            11,
            mutableList(
                leafOf(111),
                leafOf(112)
            )
        ),
        leafOf(12)
    )
)
val pathEnumerationList = PathEnumerationList.fromTreeNode(treeNode)
// (path, value)
// (1, 1)
// (1/11, 11)
// (1/11/111, 111)
// (1/12, 12)

? License

Copyright © 2023 YuitoSato.

This project is licensed under Apache 2.0.

GitHub

View Github