在数组A之后对数组B进行排序,使得引用和相等的基元保持精确的位置

时间:2013-06-06 18:14:56

标签: javascript arrays sorting

更新2

我在sort函数中添加了一个权重查找,它将性能提高了大约100%以及稳定性,因为之前的sort函数没有考虑所有类型,而1 == "1"结果是sort取决于数组的初始顺序,正如@Esailija指出的那样。

问题的目的是改进我的Answer,我喜欢这个问题,因为它被接受了,我觉得有一些性能可以挤出排序功能。我在这里问了这个问题,因为我没有很多线索可以从哪里开始 也许这会使事情更清晰

更新

我改写了完整的问题,因为很多人都说我不够具体,我尽力说出我的意思。另外,我重写了var x = { a:"A Property", x:"24th Property", obj: { a: "A Property" }, prim : 1, } x.obj.circ = x; var y = { a:"A Property", x:"24th Property", obj: { a: "A Property" }, prim : 1, } y.obj.circ = y; var z = {}; var a = [x,x,x,null,undefined,1,y,"2",x,z] var b = [z,x,x,y,undefined,1,null,"2",x,x] console.log (sort(a),sort(b,a)) 函数以更好地表达问题的意图。

  • arrayPrev 成为数组 A ),其中 A 由0到n组成元素的S' (电子

    • 元素成为
        原始类型的
        • 布尔字符串数字未定义 null
      • a 参考对象 O ,其中 O .type = [object Object] O 可以包含
        • 0到n 属性 P ,其中 P 定义为 Element plus
          • O
          • 中任何 P 的循环参考
        • 任何 O 可以包含1到n次。在 GetReferencedName(E1)的意义上=== GetReferencedName(E2) ......
      • a 参考 O ,其中 O .type = [object Array] O 的定义类似于 A
      • A
      • 中的任何 E 的循环参考
  • arrayCurr 成为与 arrayPrev
  • 相同长度的数组

以下示例说明

a

问题是,如何有效地数组B 进行排序,以便对对象的任何引用或基元的值共享完全与以前相同的位置,通过相同的 compareFunction,已排序,数组A

与上面的例子一样

Console Log

结果数组应符合规则。

  • arrayPrev 包含元素 s' b arrayCurr 包含元素 s' b[n] === a[n]
    1. arrayPrev CompareFunction C 排序。
    2. arrayCurr 按相同的 C 排序。
      • arrayCur 排序的结果是这样的,当访问位于 n arrayCur 中的 E 时,让 n 例如是5
        • 如果 E 的类型是对象 GetReferencedName(arrayCurr [n]) === GetReferencedName(arrayPrev [n])
        • 如果 E 的类型是原语 GetValue(arrayCurr [n]) === GetValue(arrayPrev [n])
        • b[5] === a[5]例如sort
      • 意味着所有元素应按类型分组,并按此值排序。
      • C 中对功能 F 的任何调用至少应在ES5之前执行,以便在不需要的情况下实现兼容性任何垫片。

我目前的方法是在 arrayPrev 中标记对象,以便在 arrayCurr 中对其进行相应的排序,然后再次删除标记。但这似乎并不那么有效。 下面是当前使用的function sort3 (curr,prev) { var weight = { "[object Undefined]":6, "[object Object]":5, "[object Null]":4, "[object String]":3, "[object Number]":2, "[object Boolean]":1 } if (prev) { //mark the objects for (var i = prev.length,j,t;i>0;i--) { t = typeof (j = prev[i]); if (j != null && t === "object") { j._pos = i; } else if (t !== "object" && t != "undefined" ) break; } } curr.sort (sorter); if (prev) { for (var k = prev.length,l,t;k>0;k--) { t = typeof (l = prev[k]); if (t === "object" && l != null) { delete l._pos; } else if (t !== "object" && t != "undefined" ) break; } } return curr; function sorter (a,b) { var tStr = Object.prototype.toString var types = [tStr.call(a),tStr.call(b)] var ret = [0,0]; if (types[0] === types[1] && types[0] === "[object Object]") { if (prev) return a._pos - b._pos else { return a === b ? 0 : 1; } } else if (types [0] !== types [1]){ return weight[types[0]] - weight[types[1]] } return a>b?1:a<b?-1:0; } } 函数。

{{1}}

继承人Fiddle以及JSPerf (随意添加您的代码段)
 和旧Fiddle

4 个答案:

答案 0 :(得分:2)

从描述中可以看出,您只需使用排序功能:

function sortOb(a,b){a=JSON.stringify(a);b=JSON.stringify(b); return a===b?0:(a>b?1:-1);}
var x = {a:1};
var y = {a:2};

var a = [1,x,2,3,y,4,x]
var b = [1,y,3,4,x,x,2]

a.sort(sortOb);
b.sort(sortOb);
console.log (a,b);

答案 1 :(得分:2)

如果您知道数组包含相同的元素(具有相同的重复次数,可能以不同的顺序),那么您可以将旧数组复制到新数组中,如下所示:

function strangeSort(curr, prev) {
    curr.length = 0;             // delete the contents of curr
    curr.push.apply(curr, prev); // append the contents of prev to curr
}

如果您不知道数组包含相同的元素,那么按照您的要求进行操作是没有意义的。

根据您链接的内容判断,您可能正在尝试确定数组是否包含相同的元素。在这种情况下,您提出的问题不是您要问的问题,而基于排序的方法可能根本不是您想要的。相反,我建议使用基于计数的算法。

  1. 比较数组的长度。如果它们不同,则数组不包含相同的元素;返回false。如果长度相等,请继续。
  2. 遍历第一个数组,并将每个元素与您看到它的次数相关联。现在ES6 Maps存在,Map可能是跟踪计数的最佳方式。如果不使用Map,则可能需要或方便地以不同方式维护不同数据类型的项目的计数。 (如果通过为对象提供新属性来维护对象的计数,请在返回之前删除新属性。)
  3. 遍历第二个数组。对于每个元素,
    1. 如果没有为元素记录计数,则返回false。
    2. 如果元素的计数为正,则将其减1。
    3. 如果元素的计数为0,则元素在第二个数组中出现的次数多于第一个数组。返回false。
  4. 返回true。
  5. 如果到达步骤4,则每个项目在第一个阵列中的显示次数与在第二个阵列中的次数相同。否则,它将在步骤3.1或3.3中检测到。如果任何项目在第一个数组中出现的次数多于第二个数组,则第一个数组会更大,并且算法将在步骤1中返回。因此,数组必须包含具有相同重复次数的相同元素。

答案 2 :(得分:1)

您的函数始终会返回sort.el的副本,但您可以更轻松:

var sort = (function () {
    var tmp;

    function sorter(a, b) {
        var types = [typeof a, typeof b];
        if (types[0] === "object" && types[1] === "object") {
            return tmp.indexOf(a) - tmp.indexOf(b); // sort by position in original
        }
        if (types[0] == "object") {
            return 1;
        }
        if (types[1] == "object") {
            return -1;
        }
        return a > b ? 1 : a < b ? -1 : 0;
    }


    return function (el) {
        if (tmp) {
            for (var i = 0; i < el.length; i++) {
                el[i] = tmp[i]; // edit el in-place, same order as tmp
            }
            return el;
        }
        tmp = [].slice.call(el); // copy original
        return tmp = el.sort(sorter); // cache result
    };

})();

请注意,我将sort.el替换为tmp和一个闭包。小提琴:http://jsfiddle.net/VLSKK/


编辑:这(以及您原来的解决方案)

  • 仅在数组包含相同元素时才有效。
  • 维护a
  • 中不同对象的顺序

  • 在被叫两次以上时不会mess up

答案 3 :(得分:-1)

试试这个

function ComplexSort (a, b)
{
     if(typeof a == "object") { 
        a = a.a; 
    } 
    if(typeof b == "object") { 
       b = b.a;
    } 
    return a-b;
}

var x = {a:1};
var y = {a:2};

var a = [1,x,2,3,y,4,x]
var b = [1,y,3,4,x,x,2]

a.sort(ComplexSort);
b.sort(ComplexSort);
console.log ("Consistent", a,b);