Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在crossfilter.js中按多个维度排序_Javascript_Sorting_Crossfilter - Fatal编程技术网

Javascript 在crossfilter.js中按多个维度排序

Javascript 在crossfilter.js中按多个维度排序,javascript,sorting,crossfilter,Javascript,Sorting,Crossfilter,我正在使用Mike Bostock的库对大型数据集进行过滤和排序。我的问题:给定一个具有多个维度的数据集,如何一次按多个维度排序? 测试数据集: [ { 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

我正在使用Mike Bostock的库对大型数据集进行过滤和排序。我的问题:给定一个具有多个维度的数据集,如何一次按多个维度排序?

测试数据集:

[
    { 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
(升序)排序:

到目前为止,我使用的方法是在所需维度上使用字符串连接:

var combos = cf.dimension(function(d) { return d.cat + '|' + d.val; });
这适用于多个基于字符串的维度,但不适用于数字维度,因为它不是自然排序(
'4'>'11'
)。我想我可以用零填充数字来完成这项工作,但是对于一个大数据集来说,这可能会很昂贵,所以我宁愿避免它这里是否有其他可行的方法,使用交叉过滤器?

允许不同维度具有不同排序方向(升序/降序)的任何解决方案的额外点数


澄清:是的,我可能需要切换到本机
数组。排序
实现。但是使用交叉过滤器的关键是它非常非常快,特别是对于大型数据集,它以一种使重复排序更快的方式缓存排序顺序。所以我真的在这里寻找一个基于交叉过滤器的答案。

我知道它没有使用交叉过滤器库,但为什么不使用排序函数来实现呢

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;
});
var combos=cf.sort(函数(a,b){ 如果(a.cat==b.cat)返回a.val


要允许不同维度具有不同的排序方向,只需使用
Array.prototype.sort
将-1替换为1,反之亦然,您可以:

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;
}
结果:

  • A 1
  • A 3
  • A 11
  • A 11
  • B 2
  • B 2
  • B 5
  • B 100
如果您想要事先
val
do:

sortByPriority.properties = ['val', 'cat'];
myArray.sort(sortByPriority);
结果:

  • A 1
  • B 2
  • B 2
  • A 3
  • B 5
  • A 11
  • A 11
  • B 100
不是一个超级有效的代码,但是,你可以改进它

更新:

您可以使用
pad
功能,使用交叉过滤器获得相同的结果

您还可以从“coll”中最大的字符串更改相同长度的焊盘大小,这将确保永远不会出现结果


查看优化:

以下是我最后做的事情:

  • 我仍然在一个新维度上使用字符串连接,但是
  • 在将度量值转换为字符串之前,我将其转换为一个正的、可比较的小数,使用交叉过滤器获得最小/最大值:

    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); 
        });
    
    var-vals=cf.dimension(函数(d){return d.val}),
    最小值=val。底部(1)[0]。val,
    偏移量=最小值<0?数学绝对值(最小值):0,
    最大值=val.top(1)[0]。val+偏移,
    valAccessor=函数(d){
    //偏移量确保正数,分数确保排序顺序
    返回((d.val+偏移量)/max.toFixed(8);
    },
    combos=cf.dimension(函数(d){
    返回d.cat+'|'+valAccessor(d);
    });
    
参见工作小提琴:


这具有正确处理负数的优势——据我所知,零填充是不可能的。看起来也一样快。缺点是它需要在数字列上创建一个新的维度,但在我的情况下,我通常在任何情况下都需要它。

我还没有测试性能,但您可以尝试d3.nest。示例代码:

var nested = d3.nest()
.key(function(d) { return d.cat; })
.sortKeys(d3.ascending)
.sortValues(compareValues)
.entries(data);
看看这里的小提琴吧:


如果运行一些jsperf:)

这是一个合理的答案,我可能需要切换到
Array.sort
实现。但是使用交叉过滤器的关键是它非常非常快,特别是对于大型数据集,它以一种使重复排序更快的方式缓存排序顺序。所以我真的在这里寻找一个基于交叉过滤器的答案。@nrabinowitz我读了交叉过滤器的源代码,它们没有扩展排序比较函数的方法,它们都是硬编码的。您需要扩展项目并对其进行更改,以提供所需的支持。对于“大数据”,我建议使用web sql或IndexedDB。它们可以确保良好的结果,并且没有UI线程,不会冻结您的UI。@nrabinowitz我再次阅读了您的代码,它给了我一个想法,所以我更新了我的答案以帮助您,我想您会喜欢:)是的,我想这是我要走的方向(尽管请参阅我问题中关于性能问题的注释)。谢谢@nrabinowitz如果你不想填充,你需要按
cat
排序,然后对具有相同值的cat对象进行分组,所以在完成后在
val
中进行排序,然后重新加入排序结果,这样你就不需要填充,但我认为不会更快,你需要创建一个jsperf.com测试来确保这一点。最后,您可以使用
webworkers
完成所有工作,如果您想更深入,可以使用pre-fork和workers实现算法,以更快地完成。不会冻结你的用户界面。但这是一个全新的项目。祝你好运。这是一个合理的答案,我可能需要切换到
Array.sort
实现。但是使用交叉过滤器的关键是它非常非常快,特别是对于大型数据集,它以一种使重复排序更快的方式缓存排序顺序。所以我真的在这里寻找一个基于交叉过滤器的答案。不幸的是,
d3.nest
与其他选项相比通常非常慢,尤其是交叉过滤器-它主要用于数据结构操作,而不是快速处理。
var combos = cf.dimension(function(d) { 
    return pad(d.cat, 10) + '|' + pad(d.val, 10); 
});
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); 
    });
var nested = d3.nest()
.key(function(d) { return d.cat; })
.sortKeys(d3.ascending)
.sortValues(compareValues)
.entries(data);