【问题标题】:Quickest way to sort a JS array based on another array's values?根据另一个数组的值对 JS 数组进行排序的最快方法?
【发布时间】:2011-03-25 00:10:07
【问题描述】:

有一些类似的帖子在敲门,但我找不到能完全解决这个特定问题的任何东西...... 我有两个配对值数组:

var A=[0.5, 0.6, 0.5, 0.7, 0.8, 0.1]
var B=['a','b','c','d','e','f']
//note: a=0.5, b=0.6, c=0.5, d=0.7, etc

对数组进行排序以使数组 A 以数字升序排列并保持数据结构的最适合处理器的方法是什么?我猜内置 array.sort(function) 会最快,但我对语法没有信心。

【问题讨论】:

    标签: javascript arrays


    【解决方案1】:

    有点老套,但确实有效。

    var A = [0.5, 0.6, 0.5, 0.7, 0.8, 0.1];
    var B = ['a', 'b', 'c', 'd', 'e', 'f'];
    
    var all = [];
    
    for (var i = 0; i < B.length; i++) {
        all.push({ 'A': A[i], 'B': B[i] });
    }
    
    all.sort(function(a, b) {
      return a.A - b.A;
    });
    
    A = [];
    B = [];
    
    for (var i = 0; i < all.length; i++) {
       A.push(all[i].A);
       B.push(all[i].B);
    }    
        
    console.log(A, B);
    

    jsFiddle.

    输出

    0.1, 0.5, 0.5, 0.6, 0.7, 0.8
    ["f", "a", "c", "b", "d", "e"]
    

    基本上,我们在一个新数组中创建具有AB 之间明确联系的对象,然后sort() 这样做。

    那我回去重建原来的两个数组。

    更新

    Már Örlygsson 在 cmets 中提出了一个很好的观点。他建议不要生成像 {A: 0.5, B: 'a'} 这样的对象,而是将 AB 值放在像 [0.5, 'a'] 这样的数组中。

    这个应该更快,但如果需要调试all 数组,它的可读性会稍差。如果您遇到性能问题,我将由您决定,请分析这两种方法并选择最快的方法。

    【讨论】:

    • 那输出不是和对其中一个数组进行排序一样吗?我在您的答案中看不到另一个的用途。
    • 从头开始,我在 jsFiddle 上运行了你的代码,另一个数组也得到了排序。尽管您应该将其包含在您的 output 部分中。
    • all.push( [ A[i], B[i] ] ) 填充all,然后用a[0] - b[0] 进行排序可能会快一些,并且使用更少的内存,尤其是当AB 变得更大时。跨度>
    • @Már 我同意你的看法,但我将按原样留下我的答案并提供注释:)
    • 这是一个更新的 jsFiddle 测试,使用数组和更少的函数调用:jsfiddle.net/Bnp8t/1
    【解决方案2】:

    我注意到上述所有解决方案都使用了地图。另一种节省一点内存的方法是创建一个索引数组,根据 A 对索引进行排序,然后根据索引重构 A 和 B。

    var A=[0.5, 0.6, 0.5, 0.7, 0.8, 0.1];
    var B=['a','b','c','d','e','f'];
    var indices = A.map(function(elem, index){return index;}); //an array of indices
    indices.sort(function (a,b) {return A[a] - A[b];});
    
    //print out the results
    for (var i = 0; i < A.length; i++)
        document.body.innerHTML += 'A: ' + A[indices[i]] + ', B: ' + B[indices[i]] + '<br>';
    

    这是jsfiddle

    编辑:受chowey's comment 启发的半单行:

    var BSorted = A.map(function(e,i){return i;})
                   .sort(function(a,b){return A[a] - A[b];})
                   .map(function(e){return B[e];});
    

    【讨论】:

    • 可以使用地图重新组装:A = A.map(function(v,i,A){return A[indices[i]]}).
    • 实际上将 map 应用于索引 indices.map(function(i){return B[i];}); 更简单一些。使用它,您实际上可以将整个事情链接到var BSorted = A.map(function(e,i){return i;}).sort(function(a,b){return A[a] - A[b];}).map(function(e){return B[e];});
    【解决方案3】:

    如果你有一个带有元组的数组而不是两个数组,那会简单得多。因为那样你就可以使用内置的Array.sort()

    var arr = [{a: 0.5, b: 'a'}, {a: 0.6, b: 'b'}, {a: 0.5, b: 'c'}, ... ];
    

    在这之后你可以写:

    arr.sort(function(x,y) { return x.a - y.a });
    

    【讨论】:

    • 您还可以使用“zip”函数从两个数组中创建一个元组数组——易于实现并且在 O(n) 中工作。
    • 用两个项目数组 ([ A[i], B[i] ]) 填充 arr 数组而不是对象可能会更快,内存效率更高。
    【解决方案4】:
    Array.prototype.swap=function(a, b)
    {
        var tmp=this[a];
        this[a]=this[b];
        this[b]=tmp;
    }
    
    function partition(array, array2, begin, end, pivot)
    {
        var piv=array[pivot];
        array.swap(pivot, end-1);
        array2.swap(pivot, end-1);
        var store=begin;
        var ix;
        for(ix=begin; ix<end-1; ++ix) {
            if(array[ix]<=piv) {
                array.swap(store, ix);
                array2.swap(store, ix);
                ++store;
            }
        }
        array.swap(end-1, store);
        array2.swap(end-1, store);
    
        return store;
    }
    
    function qsort(array, array2, begin, end)
    {
        if(end-1>begin) {
            var pivot=begin+Math.floor(Math.random()*(end-begin));
    
            pivot=partition(array, array2, begin, end, pivot);
    
            qsort(array, array2, begin, pivot);
            qsort(array, array2, pivot+1, end);
        }
    }
    

    数组用于数字, array2 用于字符串, 它们的长度必须相同。

    这是快速排序,所以时间是 O(N LogN)

    来源是literateprograms.org,许可证是MIT,修改以管理我制作的第二个数组

    【讨论】:

    • 我想知道纯 javascript 快速排序实现与原生内置版本(我认为是合并排序实现)相比性能如何。
    • 实际上,ECMA 规范声明排序算法是“实现定义的”,所以这取决于 javascript 引擎设计。也就是说,我很难相信 javascript 排序算法能够比任何现有的本机实现执行得更快。
    • 感谢您使用 google,但如果您要发布 solution,则应注明原始来源。此外,您的更改使递归调用的 begin 和 end 传递变得不必要
    • @jordancpaul 我同意,我本可以认为这是礼貌的,但我在发布此内容时很着急。我已经更新了帖子。
    【解决方案5】:

    对于任何排序算法,都需要在算法时间和其他约束(通常是内存)之间进行权衡。您可能想看看QuicksortBubble Sort,这是两种常见且非常快速的排序算法。你需要做一些小的修改,因为你实际上是在对两个数组进行排序,第一个是要排序的数据源 - 但这种改变是微不足道的。

    编辑:注意,array.sort() 对您不起作用,因为您希望 arr1 中的更改反映在 arr2 中。你得自己写排序函数

    【讨论】:

    • 我不会称冒泡排序是一个非常快的算法 :-) 也许对于非常小的或几乎排序的列表,但即便如此我更喜欢插入排序。
    • 没错,不过它在速度上的不足之处在于它的简洁性。
    • 确实很快,不是运行,而是实现:-P。
    【解决方案6】:

    之前把两个数组放在一起 排序是最简单的方法。

    var a1, b1, A= [0.5, 0.6, 0.5, 0.7, 0.8, 0.1],
    B= ['a', 'b', 'c', 'd', 'e', 'f'],    
    ab= A.map(function(itm, i){ return [itm, i]; });
    
    ab.sort(function(a, b){ return a[0]-b[0]; });
    
    B= ab.map(function(itm){
        A.push(itm[0]);
        return B[itm[1]];
    });
    A= A.splice(B.length);
    
    alert(A+'\n'+B)
    
    /*  returned value: (String)
    0.1, 0.5, 0.5, 0.6, 0.7, 0.8
    f, a, c, b, d, e
    */
    

    【讨论】:

    • 不错!这在速度方面如何比较?我需要每 10 毫秒运行一次这个函数
    【解决方案7】:

    如果可能的话,你可能会更好地实际制作一个数据结构。这样,您可以在保持结构的同时基于一个属性对$A[] 进行排序。我没有做过任何速度测试或其他任何事情,但可能是......

    A[0]['label']='a';
    A[0]['value']=0.5;
    
    A[1]['label']='b';
    A[1]['value']=0.6;
    
    A[2]['label']='c';
    A[2]['value']=0.5;
    
    A[3]['label']='d';
    A[3]['value']=0.7;
    
    A[4]['label']='e';
    A[4]['value']=0.8;
    
    A[5]['label']='f';
    A[5]['value']=0.1;
    

    【讨论】:

    • 嘿,Netscape 打来电话,它想找回它的 document.layers 对象。
    猜你喜欢
    • 2022-12-18
    • 2015-08-05
    • 2015-04-17
    • 1970-01-01
    • 2021-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-02
    相关资源
    最近更新 更多