node-relation
This module helps you manage string, numbers, object as a group.
Check the code.
import { Relationship } from 'node-relation'
let state = new Relationship().to('a', 'b')
state.nodes
state = state.to('b', 'c')
state.nodes
state = state.to('c', 'd')
state.from('c').nodes
state = state.to('d', 'a')
state.from('c').nodes
Install
You can download in npm node-relation.
npm install node-relation
How to use
Browser (umd)
<script src="https://cdn.jsdelivr.net/npm/node-relation@latest/dist/umd/index.min.js"></script>
<script>
const state = new NodeRelation.Relationship().to('a', 'b', 'c')
</script>
Browser (esnext)
import { Relationship } from 'https://cdn.jsdelivr.net/npm/node-relation@latest/dist/esm/index.min.js'
Node.js
import { Relationship } from 'node-relation'
const state = new Relationship().to('a', 'b', 'c')
Methods
The data inside the instance is immutable.
The method does not modify the data inside, it returns the result of the calculation as a new instance.
to(source: T
, ...targets: T[]
): Relationship
Creates a new refer between nodes, and returns it as a Relationship instance.
This is one-sided relationship between both nodes.
const state = new Relationship().to('language', 'English', 'Korean', 'Japanese')
language ─> English
language ─> Korean
language ─> Japanese
both(a: T
, ...b: T[]
): Relationship
Creates a new relationship between nodes, and returns it as a new Relationship instance.
Both nodes will know each other.
const A = new Relationship().to('language', 'English', 'Korean', 'Japanese')
const B = A.both('English', 'US', 'France', 'Italy')
language ─> English
language ─> Korean
language ─> Japanese
language ─> English
English <─> US
English <─> France
English <─> Italy
language ─> Korean
language ─> Japanese
all(...nodes: T[]
): Relationship
Creates a new relationship between all each other nodes, and returns it as a new Relationship instance.
All nodes will know each others.
const state = new Relationship().all('john', 'harris', 'richard')
john <─> harris
harris <─> richard
richard <─> john
from(source: T
, depth?: number
= -1): Relationship
Only the nodes that are related to the node received by the parameter are filtered and returned in a new Relationship instance.
You can control calculation depth relationship with depth parameter. If depth parameter are negative, it's will be calculate all relationship between nodes in instance. Depth parameter default value is -1.
let state = new Relationship()
.to('language', 'English', 'Korean', 'Japanese')
.both('English', 'US', 'France', 'Italy')
state.from('language').nodes
state.from('English').nodes
where(filter: (node: T
, i: number
, array: T[]
) => boolean
, depth?: number
= -1): Relationship
Returns a new relationship instance with only nodes that meet the conditions.
const state = new Relationship()
.both('English', 'US', 'France', 'Italy')
state.where((v) => v === 'English').nodes
without(...nodes: T[]
): T[]
Returns the remaining nodes except those received as parameters from the current relationship instance.
const state = new Relationship()
.to('language', 'English', 'Korean', 'Japanese')
state.from('language').nodes
state.from('language').without('language')
unlinkTo(source: T
, ...targets: T[]
): Relationship
Deletes the relationship between nodes and returns it as a new Relationship instance.
This is one-sided cut off between both nodes.
let state = new Relationship()
.to('a', 'b', 'c')
state = state.unlinkTo('a', 'b')
state.nodes
unlinkBoth(a: T
, ...b: T[]
): Relationship
Deletes the relationship between nodes and returns it as a new Relationship instance.
Both nodes will cut off each other.
let state = new Relationship()
.both('a', 'b', 'c')
state = state.unlinkBoth('a', 'b')
state.nodes
drop(...nodes: T[]
): Relationship
Delete the node. If the node associated with the deleted node is isolated, it is deleted together. Returns the result with a new Relationship instance.
let state = new Relationship()
.to('a', 'b', 'c')
state = state.drop('a')
state.nodes
let stateB = new Relationship()
.to('a', 'b')
.to('b', 'c')
stateB = stateB.drop('b')
stateB.nodes
let stateC = new Relationship()
.to('a', 'b')
.to('b', 'c')
.to('c', 'a')
stateC = stateC.drop('b')
stateC.nodes
has(node: T
): boolean
Returns whether the instance contains that node.
const state = new Relationship()
.to('a', 'b', 'c')
const exists = state.has('a')
hasAll(...nodes: T[]
): boolean
Returns whether the instance contains all of its nodes.
const state = new Relationship()
.to('a', 'b', 'c')
const existsAll = state.hasAll('a', 'b')
weight(node: T
, log?: boolean
= false
): number
Returns how many nodes are related to the node received by the parameter.
const state = new Relationship()
.to('a', 'd')
.to('b', 'd')
.to('c', 'd')
const weight = state.weight('d')
weights(log?: boolean
= false
, normalize?: boolean
= false
): Map<T, number>
Returns the weight of all nodes. Check the weight
method.
const state = new Relationship()
.to('a', 'd')
.to('b', 'd')
.to('c', 'd')
.to('d', 'a')
const weights = state.weights()
const normalizedWeights = state.weights(false, true)
depth(source: T
, target: T
, log?: boolean
= false
): number
Returns the found minimum depth to between source to target.
const state = new Relationship()
.to('a', 'b')
state.depth('a', 'b')
state.depth('b', 'a')
distance(a: T
, b: T
, log?: boolean
= false
): number
Returns the found minimum distance to between both nodes. This is same as Math.min(this.depth(a, b), this.depth(b, a))
const state = new Relationship()
.to('a', 'b')
.to('b', 'c')
state.distance('b', 'a')
state.distance('a', 'c')
merge(...datasets: RelationData[]
): Relationship
Merge a relation dataset with this instance, and returns it as a new Relationship instance.
If there is a non-overlapping dataset, It will be append to instance.
const A = state.to('user-a', 'user-b')
const B = state.to('user-c', 'user-d')
const C = A.merge(B.dataset).nodes
raw(node: T
): T
|undefined
This method for instance that useEqual
options. It returns a original value from node
parameter.
It will be useful when using between returned Map from nodeset
, oneHot
, label
getters and weights
method.
const useEqual = true
const state = new Relationship(undefined, useEqual).to({ name: 'a' }, { name: 'b' })
const weights = state.weights()
weights.get({ name: 'b' })
const raw = state.raw({ name: 'b' })
weights.get(raw)
clear(): void
Destroy the data in the instance. It is used for garbage collector.
constructor(dataset?: RelationData[]
, useEqual?: boolean
= false
): Relationship
You can pass dataset parameter to init this instance.
The RelationData
is type of 2-dimensional tuple array. Check dataset getter description.
const state = new Relationship([ ['a', ['b', 'c', 'd']] ])
const clone = new Relationship(state.dataset)
If you want ignore strict references to variables, You can use the useEqual
option. This helps you treat other objects as the same variable.
const useEqual = true
let state = new Relationship(null, useEqual)
state = state.to({ a: 1 }, { a: 2 })
state = state.to({ a: 1 }, { a: 3 })
state.nodes
(getter)
dataset: RelationData[]
Returns as 2-dimensional array of relationships between nodes in the instance. Relationships are returned to saveable data-type(json).
const state = new Relationship().to('a', 'b').to('b', 'c', 'd')
state.dataset
(getter)
nodes: T[]
Get all nodes from the instance.
const state = new Relationship().to('a', 'b').to('b', 'c')
state.nodes
(getter)
nodeset: Set<T>
Get all nodes as Set object from the instance.
const state = new Relationship().to('a', 'b').to('b', 'c')
state.nodeset
(getter)
oneHot: Map<T, number[]>
Get all nodes as one-hot vectors from the instance. It could be used as dataset for machine learning.
const state = new Relationship().to('a', 'b').to('b', 'c')
const vectors = state.oneHot
vectors
Array.from(vectors.values())
(getter)
zeroVector: number[]
Get a 1-dimensional vector that was filled 0. The vector's size are same as nodes length of instance. This is useful for representing data that does not belong to anything. It could be used as dataset for machine learning.
const state = new Relationship().to('a', 'b').to('b', 'c')
const vectors = state.oneHot
const zeroVector = state.zeroVector
const allVectors = [zeroVector, ...vectors.values()]
(getter)
label: Map<T, number>
Get all nodes as labeled vector from the instance. It could be used as dataset for machine learning.
const state = new Relationship().to('a', 'b').to('b', 'c')
const vector = state.label
vector
Array.from(vector.values())
(getter)
clusters: T[][]
Returns the clustering models of this instance in the form of a two-dimensional array.
let state = new Relationship().to('a', 'b', 'c').to('d', 'e')
state.clusters
state = state.to('e', 'a')
state.clusters
(getter)
reverse: Relationship
Returns the instance in which the relationship of the node is reversed.
const state = new Relationship().to('a', 'b').to('b', 'c')
state.reverse.from('c').nodes
Try it simply
Applying (Advanced usage, with Typescript)
import { Relationship } from 'node-relation'
type ServerName = 'server-a' | 'server-b'
class User {
...
}
const userA = new User
const userB = new User
const userC = new User
let state: Relationship<ServerName|User> = new Relationship
state = state.to('server-a', userA, userB)
state = state.to('server-b', userC)
console.log( state.from('server-b').without('server-b') )
import { Relationship } from 'node-relation/dist/umd/raw/index'
const sentence = 'what will the fat cat sit on'
const words = sentence.split(' ')
const state = new Relationship<string>()
words.forEach((word, i) => {
const next = words[i+1]
if (next) {
state.to(word, next)
}
})
const oneHot = state.oneHot
const oneHotVectors = Array.from(oneHot.values())
const label = state.label
const labels = Array.from(label.values())
Migration 3.x.x to 4.x.x
Check readme