Javascript: 根据第一个数组的排序结果对多维数组进行排序

5

我有一个类似于这样的数组:

var ary1 = new Array("d", "a", "b", "c");
var ary2 = new Array("ee", "rr", "yy", "mm");

var mdAry = new Array(ary1, ary2);

在整体上,ary1和ary2的索引信息是相关的。

d ee
a rr
b yy
c mm

我可以使用sort()函数对ary1进行排序,结果如下:
a
b
c
d

但是如果我独立地对ary2进行排序,我会得到:
ee
mm
rr
yy

当列出ary1和ary2的连接时,它们在视觉上被分开。我能否检索ary1的排序解决方案并将其应用于ary2?我想要这个:

a rr
b yy
c mm
d ee

如果不行,那么能否对mdAry进行排序,以便将mdAry [0]的排序解决方案应用于其余索引?

最好将数据放在行中而不是列中,这样你就可以回到排序行的方式,这很容易。 - Halcyon
很不幸,我正在填充一个列表框GUI。第一列是a、b、c、d,第二列是rr、yy、mm、ee的内容。一旦显示,每个列表框项行都与一个资产相关的信息。 - David Torno
你需要处理可能的重复条目吗?比如 [a, a, b, c]? - sixFingers
1
我已经有一个去重的函数了,所以我只是想弄清楚排序问题。 - David Torno
1
仅仅因为你正在填充一个列表框GUI并不意味着你必须使用多维数组。你可以非常容易地重写你的代码,使用对象数组,比如[{col1:'d', col2:'ee'}, {col1:'a', col2:'rr'}, {col1:'b', col2:'mm'}, {col1:'c', col2:'yy'}]。在我看来,这是一种更优越的存储和处理数据的方式,有很多原因,其中最重要的是你可以对其进行排序,相关数据会保持在一起!当元素应该相关时,将数据放入单独的数组中就没有意义了。不要使用嵌套数组来存储行类型数据! - ErikE
为了好玩,这里有一个受 PHP 启发的 array_multisort() - Ja͢ck
5个回答

3
如果您的数组元素相关,请将它们存储在一起:
var arr = [
  {x: 'd', y: 'ee'}, 
  {x: 'a', y: 'rr'}, 
  {x: 'b', y: 'yy'},
  {x: 'c', y: 'mm'}
];

arr.sort(function(a, b) {
  if (a.x != b.x) {
      return a.x < b.x ? -1 : 1;
  }
  return 0;
});

1
如果你的数组项是相关的,那么就把它们存放在一起...数据结构有人懂吗?+1 - Gabriel
我想给你点赞,但是你的排序函数尝试对字符串值进行数学运算,所以我不能。 - ErikE
而且你确保它是一种稳定排序,也很好。 +1。 - ErikE

1

一种实现这个目标的方法是将数据结构转换为更易于排序的形式,然后再进行转换。

var ary1  = ["d", "a", "b", "c"],
    ary2  = ["ee", "rr", "mm", "yy"]
    mdAry = [ary1, ary2];

// convert to form [[d, ee], [a, rr], ..]
var tmp = mdAry[0].map(function (e, i) {
    return [e, mdAry[1][i]];
});
// sort this
tmp.sort(function (a, b) {return a[0] > b[0];});
// revert to [[a, b, ..], [rr, mm, ..]]
tmp.forEach(function (e, i) {
    mdAry[0][i] = e[0];
    mdAry[1][i] = e[1];
});
// output
mdAry;
// [["a", "b", "c", "d"], ["rr", "mm", "yy", "ee"]]

我认为这是最直观的解决方案。如果在 UI 组件中显示是瓶颈而不是排序,那么效率也足够高。 - Rusty Rob
我想到的另一种方法是编写自己实现的排序算法,适用于在第二个数组上进行相同的转换,但在JavaScript中可能会变得混乱。第三种想法与第一种类似,但使用索引而不是ary2值来表示tmp [i] [1],然后循环修改其他数组中的这些索引 - 优点是您可以扩展它而不像复制所有值一样占用太多内存。 - Paul S.
是的 - 对索引进行排序是一种选择,例如在Python中,它看起来像sorted(range(len(myList)),key=myList.getitem)。 - Rusty Rob

1

除了上述方法,您还可以从第一个数组中获取一个排序的“结果”,并将其应用于任何其他相关列表:

function getSorter(model) {
    var clone = model.slice(0).sort();
    var sortResult = model.map(function(item) { return clone.indexOf(item); });

    return function(anyOtherArray) {
        result = [];
        sortResult.forEach(function(idx, i) {
            result[idx] = anyOtherArray[i];
        });
        return result;
    }
}

然后,
var arr = ["d", "a", "b", "c"];
var arr2 = ["ee", "rr", "yy", "mm"];

var preparedSorter = getSorter(arr);
preparedSorter(arr2); 
//=> ["rr", "yy", "mm", "ee"];

或者,
multidimensional = [arr, arr2];
multidimensional.map(getSorter(arr)); 
// => [["a", "b", "c", "d"], ["rr", "yy", "mm", "ee"]]

如果数组中存在匹配的值,即getSorter(['a', 'b', 'a', 'b'])将产生一个形式为[0, 0, 2, 2]sortResult,因此result将以索引1为未定义和长度3而出现错误。 - Paul S.
你说得对,它只适用于独特的成员。我会看看能否修复它。 - matehat

0
在你的例子中,结果应该是(如果我理解正确的话)。
a rr
b mm
c yy
d ee

所以这个应该能完成工作:

Array.prototype.sortRelated = function(related) {
    var clone = this.slice(0), 
        sortedRelated = [];
    clone.sort();

    for(var i = 0; i < this.length; i ++) {
        sortedRelated[clone.indexOf(this[i])] = related[i];
    }

    return sortedRelated;
}

var ary1 = new Array("d", "a", "b", "c");
var ary2 = new Array("ee", "rr", "mm", "yy");

var sorted = ary1.sortRelated(ary2);

这里有一个工作演示:http://jsfiddle.net/cwgN8/


0
你可以将它们合并成一个具有两个属性的单一对象,按照第一个属性进行排序,最后再分离回来(在这里查看演示):
function sortBoth(ary1, ary2) {
    var merged = [];
    for (var i=0; i < ary1.length; i++) merged.push({'ary1': ary1[i], 'ary2': ary2[i]});
    merged.sort(function(o1, o2) { return ((o1.ary1 < o2.ary1) ? -1 : ((o1.ary1 == o2.ary1) ? 0 : 1)); });
    for (var i=0; i < merged.length; i++) { ary1[i] = merged[i].ary1; ary2[i] = merged[i].ary2; }
}

var ary1 = new Array("d", "a", "b", "c");
var ary2 = new Array("ee", "rr", "mm", "yy");

console.log(ary1);
console.log(ary2);

sortBoth(ary1, ary2);

console.log(ary1);
console.log(ary2);

输出:

[ "d",  "a",  "b",  "c"]
["ee", "rr", "mm", "yy"]
[ "a",  "b",  "c",  "d"]
["rr", "mm", "yy", "ee"] 

@DavidTorno,它的效果很好,但我忍不住要说,这只是在不太理想的数据存储策略上贴了个创可贴。 - ErikE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接