Wednesday, June 27, 2007

the way forward

I think I have found the way forward! And it's Array.prototype.groupBy.

So the "show a list of things grouped according to some criteria" functionality is one of the main sources of slowness in MGTD alpha. While adding the "go faster" code (work in progress in the svn trunk but not released yet) I attempted a rewrite of the grouped list functionality to be more efficient, but the new version was quite ugly and inelegant and I was finding bugs that I was having trouble squashing. Anyway I was reading an article about some new features in ruby 1.9 and it mentioned groupBy method for arrays. It didn't really describe it much but just the mention of it was enough and later that night I scribbled this on a piece of paper.

merge(Array.prototype,{

  groupBy: function(callback) {
    var result = {};
    var leftOverGroup = '__NONE__';
    this.each(function(item) {
      var groups = callback(item);
      if (groups.length > 0) {
        groups.each(function(group) {
          if (!result[group])
            result[group] = [];
          result[group].push(item);
        });
      }
      else {
        if (!result[leftOverGroup])
          result[leftOverGroup] = [];
        result[leftOverGroup].push(item);
      }
    });
    return result;
  }

});
or at least something pretty close to it. It pretty much does the same thing as my existing code but it's much cleaner and much more ruby-esque. It also removes the presentation layer from the logic which has to be a good thing. The function you pass in should return an array of "groups" that the item belongs to. Example usage:
var test = ["Apples","Anchovies","Cupcakes","Zorro"].groupBy(function(x){
  return x == "Zorro" ? [] : [x.substr(0,1)];
});

/*
test is now this:
{
  A: ["Apples","Anchovies"],
  C: ["Cupcakes"],
  __NONE__: ["Zorro"]
}
*/

// possible usage in MGTD
var list = config.indexedTags.tagLists.Project.groupBy(function(t){
  config.indexedTags.indexes[t].Area;
});
Note that __NONE__ is where the leftovers go so for example projects with no area, or actions with no context. There's still some work to do on rendering and sorting the result, and actually it still won't give me projects with no next actions, but I'm confident that's it's a step in the right direction.