Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/quiet-moments-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": minor
---

Add support for ordering in Graph traversal
37 changes: 27 additions & 10 deletions packages/effect/src/Graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
* @since 3.18.0
*/

import * as Arr from "./Array.js"
import * as Data from "./Data.js"
import * as Equal from "./Equal.js"
import { dual } from "./Function.js"
import * as Hash from "./Hash.js"
import type { Inspectable } from "./Inspectable.js"
import { format, NodeInspectSymbol } from "./Inspectable.js"
import * as Option from "./Option.js"
import type * as Order from "./Order.js"
import type { Pipeable } from "./Pipeable.js"
import { pipeArguments } from "./Pipeable.js"
import type { Mutable } from "./Types.js"
Expand Down Expand Up @@ -3159,6 +3161,7 @@ export const entries = <T, N>(walker: Walker<T, N>): Iterable<[T, N]> =>
export interface SearchConfig {
readonly start?: Array<NodeIndex>
readonly direction?: Direction
readonly order?: Order.Order<NodeIndex>
}

/**
Expand Down Expand Up @@ -3199,6 +3202,7 @@ export const dfs = <N, E, T extends Kind = "directed">(
): NodeWalker<N> => {
const start = config.start ?? []
const direction = config.direction ?? "outgoing"
const order = config.order

// Validate that all start nodes exist
for (const nodeIndex of start) {
Expand All @@ -3209,7 +3213,9 @@ export const dfs = <N, E, T extends Kind = "directed">(

return new Walker((f) => ({
[Symbol.iterator]: () => {
const stack = [...start]
// Sort start nodes if order is provided
const sortedStart = order ? Arr.sort(start, order) : start
const stack = [...sortedStart]
const discovered = new Set<NodeIndex>()

const nextMapped = () => {
Expand All @@ -3228,8 +3234,10 @@ export const dfs = <N, E, T extends Kind = "directed">(
}

const neighbors = neighborsDirected(graph, current, direction)
for (let i = neighbors.length - 1; i >= 0; i--) {
const neighbor = neighbors[i]
// Sort neighbors if order is provided
const sortedNeighbors = order ? Arr.sort(neighbors, order) : neighbors
for (let i = sortedNeighbors.length - 1; i >= 0; i--) {
const neighbor = sortedNeighbors[i]
if (!discovered.has(neighbor)) {
stack.push(neighbor)
}
Expand Down Expand Up @@ -3284,6 +3292,7 @@ export const bfs = <N, E, T extends Kind = "directed">(
): NodeWalker<N> => {
const start = config.start ?? []
const direction = config.direction ?? "outgoing"
const order = config.order

// Validate that all start nodes exist
for (const nodeIndex of start) {
Expand All @@ -3294,7 +3303,9 @@ export const bfs = <N, E, T extends Kind = "directed">(

return new Walker((f) => ({
[Symbol.iterator]: () => {
const queue = [...start]
// Sort start nodes if order is provided
const sortedStart = order ? Arr.sort(start, order) : start
const queue = [...sortedStart]
const discovered = new Set<NodeIndex>()

const nextMapped = () => {
Expand All @@ -3305,7 +3316,9 @@ export const bfs = <N, E, T extends Kind = "directed">(
discovered.add(current)

const neighbors = neighborsDirected(graph, current, direction)
for (const neighbor of neighbors) {
// Sort neighbors if order is provided
const sortedNeighbors = order ? Arr.sort(neighbors, order) : neighbors
for (const neighbor of sortedNeighbors) {
if (!discovered.has(neighbor)) {
queue.push(neighbor)
}
Expand Down Expand Up @@ -3500,6 +3513,7 @@ export const dfsPostOrder = <N, E, T extends Kind = "directed">(
): NodeWalker<N> => {
const start = config.start ?? []
const direction = config.direction ?? "outgoing"
const order = config.order

// Validate that all start nodes exist
for (const nodeIndex of start) {
Expand All @@ -3514,9 +3528,10 @@ export const dfsPostOrder = <N, E, T extends Kind = "directed">(
const discovered = new Set<NodeIndex>()
const finished = new Set<NodeIndex>()

// Initialize stack with start nodes
for (let i = start.length - 1; i >= 0; i--) {
stack.push({ node: start[i], visitedChildren: false })
// Sort start nodes if order is provided, then initialize stack in reverse order
const sortedStart = order ? Arr.sort(start, order) : start
for (let i = sortedStart.length - 1; i >= 0; i--) {
stack.push({ node: sortedStart[i], visitedChildren: false })
}

const nextMapped = () => {
Expand All @@ -3532,8 +3547,10 @@ export const dfsPostOrder = <N, E, T extends Kind = "directed">(
current.visitedChildren = true
const neighbors = neighborsDirected(graph, current.node, direction)

for (let i = neighbors.length - 1; i >= 0; i--) {
const neighbor = neighbors[i]
// Sort neighbors if order is provided
const sortedNeighbors = order ? Arr.sort(neighbors, order) : neighbors
for (let i = sortedNeighbors.length - 1; i >= 0; i--) {
const neighbor = sortedNeighbors[i]
if (!discovered.has(neighbor) && !finished.has(neighbor)) {
stack.push({ node: neighbor, visitedChildren: false })
}
Expand Down
Loading