/*
  An Aggregator aggregates a list of data points.
  It counts the number of data points in each category.
  The category is determined by calling a function with each data point,
  this function is passed in to the by(fn) method.
  The API of aggregator is fluent,
  	var agg = new Aggregator();
  	var results = agg.aggregate(list).by(key_function)
	results is then a list of objects, objects have the following structure
		{
			by: key_function(data_point),
			count: x<int>
			children: []
		}
	where 'by' has the value of the key_function applied to a data point in the list,
	count is the number of occurences of that particular category,
	and children contains the actual data points that are aggregateed
	into this particular category
*/
function Aggregator() {
	var _original;
}

Aggregator.prototype.aggregate = function(list) {
	this._original = list;
	return this;
}

/*
	Does the aggregation of the list of data points.
	Internally it first transforms the list into a dictionary,
	with the keys being the category, obtained by calling getKey(x)
	on each data point.
	The value of each key is a dictionary containing the count, as well as
	a list of data points making up this category.
	  {
			'key': {
				'count' : 1
				'children': []
			}
	  }
  This is then flattened into an array of objects, which has the structure
	  {
			'by': category,
			'count': x <int>,
			'children': []
	  }
*/
Aggregator.prototype.by = function(getKey) {
  var agg = {}, aggBy, arr = [];
  this._original.forEach(function(value, index, array) {
    aggBy = getKey(value);
    agg[aggBy] = agg[aggBy] || {'count': 0, 'children': []};
    agg[aggBy].count++;
    agg[aggBy].children.push(value);
  });
  for (aggBy in agg) {
    arr.push({
    	'by': aggBy,
    	'count': agg[aggBy].count,
    	'children': agg[aggBy].children
    });
  }
  return arr;
}

@@ -1043,22 +1043,21 @@
 calling 
-getKey
+keyFn
 (x)%0A%09on 
@@ -1344,16 +1344,24 @@
 %09%09'by': 
+name_of_
 category
@@ -1379,28 +1379,24 @@
 ': x
- %3C
+_
 int
-%3E
 ,%0A%09%09%09'
-children
+values
 ': %5B
@@ -1444,243 +1444,958 @@
 ion(
-getKey
+keyFn
 ) %7B%0A
-  
+%09
 var 
-agg = %7B%7D, aggBy, arr = %5B%5D;%0A  this._original.forEach(function(value, index, array) %7B%0A    aggBy = getKey(value);%0A    agg%5BaggBy%5D = agg%5BaggBy%5D %7C%7C %7B'count': 0, 'children': %5B%5D%7D;%0A    agg%5BaggBy%5D.count++;%0A    agg%5BaggBy%5D.children
+splt = new Splitter();%0A%09var splits = splt.split(this._original).by(keyFn);%0A%09splits.forEach(function(value, index, array) %7B%0A%09%09value.count = value.values.length;%0A%09%7D);%0A  return splits;%0A%7D%0A%0A/*%0A%09Splits an array of objects into a number of categories by applying%0A%09the keyFn to it.%0A%09%5Bobj1, obj2, obj3, obj4%5D%0A%09-%3E %5Bcategory1, category2%5D%0A%09where each category is of the structure:%0A%09%09%7B%0A%09%09%09'by': name_of_category,%0A%09%09%09'values': %5Barr, of, values, that, belong, to, this, category%5D%0A%09%09%7D%0A*/%0Afunction Splitter() %7B%0A%09var _original;%0A%7D%0A%0ASplitter.prototype.split = function(list) %7B%0A%09this._original = list;%09%0A%09return this;%0A%7D%0A%0A/*%0A%09keyFn is the function that is applied to each value in the list%0A%09to get the the category each value will be keyed by%0A*/%0ASplitter.prototype.by = function(keyFn) %7B%0A%09var splt = %7B%7D, splitBy, arr = %5B%5D;%0A%09this._original.forEach(function(value, index, array) %7B%0A%09%09splitBy = keyFn(value);%0A%09%09splt%5BsplitBy%5D = splt%5BsplitBy%5D %7C%7C %5B%5D;%0A%09%09splt%5BsplitBy%5D
 .pus
@@ -2408,41 +2408,40 @@
 e);%0A
-  
+%09
 %7D);%0A
-  
+%09
 for (
-agg
+split
 By in 
-agg) %7B%0A    
+splt) %7B%0A%09%09
 arr.
@@ -2450,110 +2450,52 @@
 sh(%7B
-%0A    %09'
+ 
 by
-'
 : 
-aggBy,%0A    %09'count': agg%5BaggBy%5D.count,%0A    %09'children': agg%5BaggBy%5D.children%0A    %7D);%0A  %7D%0A  
+splitBy, values: splt%5BsplitBy%5D %7D);%0A%09%7D%0A%09
 retu

Refactor Aggregator