我正在使用Mike Bostock的crossfilter库来过滤和排序大型数据集。我的问题:鉴于具有多个维度的数据集,我如何一次对多个维度进行排序?
测试数据集:
[
{ cat: "A", val:1 },
{ cat: "B", val:2 },
{ cat: "A", val:11 },
{ cat: "B", val:5 },
{ cat: "A", val:3 },
{ cat: "B", val:2 },
{ cat: "A", val:11 },
{ cat: "B", val:100 }
]
所需输出的示例,按cat, val
(升序)排序:
[
{ cat: "A", val:1 },
{ cat: "A", val:3 },
{ cat: "A", val:11 },
{ cat: "A", val:11 },
{ cat: "B", val:2 },
{ cat: "B", val:2 },
{ cat: "B", val:5 },
{ cat: "B", val:100 }
]
到目前为止,我使用的方法是在所需的维度上使用字符串连接:
var combos = cf.dimension(function(d) { return d.cat + '|' + d.val; });
这适用于多个基于字符串的维度,但不适用于数字维度,因为它不是自然排序('4' > '11'
)。我想我可以在数字上使用零填充来完成这项工作,但是对于大型数据集来说这可能会变得昂贵,所以我宁愿避免使用它。 使用crossfilter还有其他可行方法吗?
允许不同维度具有不同排序方向(升序/降序)的任何解决方案的加分点。
澄清:是的,我可能需要切换到原生Array.sort
实施。但是使用crossfilter的重点在于它非常非常快,特别是对于大型数据集,它以一种使重复排序更快的方式缓存排序顺序。所以我真的在这里寻找一个基于crossfilter的答案。
答案 0 :(得分:2)
我知道它不使用crossfilter库,但为什么不使用sort函数来执行此操作?
var combos = cf.sort(function(a,b) {
if(a.cat == b.cat) return a.val < b.val ? -1 : 1;
return a.cat < b.cat ? -1 : 1;
});
请参阅http://jsfiddle.net/cQXNK/5/
要允许不同的维度具有不同的排序方向,只需将-1换成1,反之亦然
答案 1 :(得分:1)
使用Array.prototype.sort
,您可以:
function sortByPriority(a, b) {
var p = sortByPriority.properties;
function pad (str, max) {
str = String(str);
return str.length < max ? pad("0" + str, max) : str;
}
if (!p) {
return a - b;
}
var ar ='', br = '';
for (var i = 0, max = p.length; i < max; i++) {
ar += pad(a[p[i]], 10);
br += pad(b[p[i]], 10);
}
return ar == br ? 0 : ar > br ? 1 : - 1;
}
使用方法:
排序cat
然后val
sortByPriority.properties = ['cat', 'val'];
myArray.sort(sortByPriority);
结果:
如果您希望先前val
执行:
sortByPriority.properties = ['val', 'cat'];
myArray.sort(sortByPriority);
结果:
不是一个超级有效的代码,但你可以改进它。
<强>更新强>
您可以使用pad
函数使用crossfilter获得相同的结果,查看this jsfiddle。
var combos = cf.dimension(function(d) {
return pad(d.cat, 10) + '|' + pad(d.val, 10);
});
你也可以用“coll”中最大的字符串改变打击垫大小相同的长度,这样可以确保结果。
答案 2 :(得分:1)
这是我最终做的事情:
我将测量值转换为正数,可比较的小数,然后将其转换为字符串,使用crossfilter获取最小值/最大值:
var vals = cf.dimension(function(d) { return d.val }),
min = vals.bottom(1)[0].val,
offset = min < 0 ? Math.abs(min) : 0,
max = vals.top(1)[0].val + offset,
valAccessor = function(d) {
// offset ensures positive numbers, fraction ensures sort order
return ((d.val + offset) / max).toFixed(8);
},
combos = cf.dimension(function(d) {
return d.cat + '|' + valAccessor(d);
});
见工作小提琴:http://jsfiddle.net/nrabinowitz/cQXNK/9/
这具有正确处理负数的优点 - 据我所知,零填充是不可能的。它似乎同样快。缺点是它需要在数字列上创建一个新维度,但在我的情况下,我通常要求在任何情况下。
答案 3 :(得分:0)
我没有测试过表现,但你可以给d3.nest一个去。示例代码:
var nested = d3.nest()
.key(function(d) { return d.cat; })
.sortKeys(d3.ascending)
.sortValues(compareValues)
.entries(data);
在这里看到整个小提琴:http://jsfiddle.net/RFontana/bZX7Q/
让我知道如果你运行一些jsperf会得到什么结果:)