|
11 | 11 |
|
12 | 12 | var d3 = require('d3');
|
13 | 13 |
|
14 |
| -// flattenUnique :: String -> [[String]] -> Object |
15 |
| -function flattenUnique(axisLetter, data) { |
16 |
| - var traceLines = data.map(function(d) {return d[axisLetter];}); |
| 14 | +// flattenUniqueSort :: String -> Function -> [[String]] -> [String] |
| 15 | +function flattenUniqueSort(axisLetter, sortFunction, data) { |
| 16 | + |
| 17 | + // Bisection based insertion sort of distinct values for logarithmic time complexity. |
17 | 18 | // Can't use a hashmap, which is O(1), because ES5 maps coerce keys to strings. If it ever becomes a bottleneck,
|
18 | 19 | // code can be separated: a hashmap (JS object) based version if all values encountered are strings; and
|
19 |
| - // downgrading to this O(n) array on the first encounter of a non-string value. |
20 |
| - // Another possible speedup is bisection, but it's probably slower on the small array |
21 |
| - // sizes typical of categorical axis values. |
| 20 | + // downgrading to this O(log(n)) array on the first encounter of a non-string value. |
| 21 | + |
22 | 22 | var categoryArray = [];
|
23 |
| - var i, j, tracePoints, category; |
| 23 | + |
| 24 | + var traceLines = data.map(function(d) {return d[axisLetter];}); |
| 25 | + |
| 26 | + var i, j, tracePoints, category, insertionIndex; |
| 27 | + |
| 28 | + var bisector = d3.bisector(sortFunction).left; |
| 29 | + |
24 | 30 | for(i = 0; i < traceLines.length; i++) {
|
| 31 | + |
25 | 32 | tracePoints = traceLines[i];
|
| 33 | + |
26 | 34 | for(j = 0; j < tracePoints.length; j++) {
|
| 35 | + |
27 | 36 | category = tracePoints[j];
|
| 37 | + |
| 38 | + // skip loop: ignore null and undefined categories |
28 | 39 | if(category === null || category === undefined) continue;
|
29 |
| - if(categoryArray.indexOf(category) === -1) { |
30 |
| - categoryArray.push(category); |
31 |
| - } |
| 40 | + |
| 41 | + insertionIndex = bisector(categoryArray, category); |
| 42 | + |
| 43 | + // skip loop on already encountered values |
| 44 | + if(insertionIndex < categoryArray.length - 1 && categoryArray[insertionIndex] === category) continue; |
| 45 | + |
| 46 | + // insert value |
| 47 | + categoryArray.splice(insertionIndex, 0, category); |
32 | 48 | }
|
33 | 49 | }
|
34 |
| - return categoryArray; |
35 |
| -} |
36 | 50 |
|
37 |
| -// flattenUniqueSort :: String -> Function -> [[String]] -> [String] |
38 |
| -function flattenUniqueSort(axisLetter, sortFunction, data) { |
39 |
| - return flattenUnique(axisLetter, data).sort(sortFunction); |
| 51 | + return categoryArray; |
40 | 52 | }
|
41 | 53 |
|
42 | 54 |
|
|
0 commit comments