TSort

TSort is a JavaScript version of Ruby’s TSort module, which provides topological sort capability to data structures.

// In the browser
JS.require('JS.TSort', function(TSort) { ... });

// In CommonJS
var TSort = require('jsclass/src/tsort').TSort;

The canonical example of this is determining how a set of dependent tasks should be sorted such that each task comes after those it depends on in the list. One way to represent this information may be as a task table:

var tasks = new Tasks({
    'eat breakfast': ['serve'],
    'serve':         ['cook'],
    'cook':          ['buy bacon', 'buy eggs'],
    'buy bacon':     [],
    'buy eggs':      []
});

(This example is borrowed from the excellent Getting to know the Ruby standard library blog.)

This table represents each task involved in serving breakfast. The tasks are the keys in the table, and each task maps to the list of tasks which must be done immediately before it. We want to to sort all our tasks into a linear list so we can process them in the correct order, and TSort lets us do that.

To use TSort, our Tasks class must implement two methods. tsortEachNode must take a callback function and context and yield each task in the set to the callback. tsortEachChild must accept an individual task and yield each of its direct children. We can implement this simply:

var Tasks = new Class({
    include: TSort,

    initialize: function(table) {
        this.table = table;
    },

    tsortEachNode: function(block, context) {
        for (var task in this.table) {
            if (this.table.hasOwnProperty(task))
                block.call(context, task);
        }
    },

    tsortEachChild: function(task, block, context) {
        var tasks = this.table[task];
        for (var i = 0, n = tasks.length; i < n; i++)
            block.call(context, tasks[i]);
    }
});

Once we’ve told TSort how to traverse our list of tasks, it can sort the dependent tasks out for us:

tasks.tsort()
// -> ['buy bacon', 'buy eggs', 'cook', 'serve', 'eat breakfast']

We now have a flat list of the tasks and can iterate over them in order, knowing that each task will have all its dependencies run before it in the list.

Note that TSort sorts based on the how objects are related to each other in a graph, not by how they compare using comparison methods.