关于javascript:排序数组项并保留相同元素的顺序

Sort array items and preserve order of same elements

假设我有这个数组:

1
2
3
4
5
6
var array = [
  { name:"border-color", value:"#CCCCCC" },
  { name:"color", value:"#FFFFFF" },
  { name:"background-color", value:"rgb(0, 0, 0)" },
  { name:"background-color", value:"rgba(0, 0, 0, .5)" }
];

此函数用于按名称对数组进行排序:

1
2
3
4
5
array.sort(function(a, b) {
  if (a.name < b.name) return -1;
  if (a.name > b.name) return 1;
  return 0;
});

以及ECMAScript语言规范,它们告诉我:

The sort is not necessarily stable (that is, elements that compare
equal do not necessarily remain in their original order).

因此,排序后,名称=背景色的两个项目可能以任何顺序出现,即:

1
2
3
4
5
[
  { name:"background-color", value:"rgb(0, 0, 0)" },
  { name:"background-color", value:"rgba(0, 0, 0, .5)" },
  ...
]

1
2
3
4
5
[
  { name:"background-color", value:"rgba(0, 0, 0, .5)" },
  { name:"background-color", value:"rgb(0, 0, 0)" },
  ...
]

如何对数组进行排序,以便具有相同名称的项保持其相对顺序?我不想硬编码任何东西。


理论上,在排序之前,您可以跟踪数组中的索引,并在排序时将其考虑在内。

1
2
3
4
5
6
7
8
9
10
11
12
13
var sortArray = yourarray.map(function(data, idx){
    return {idx:idx, data:data}
})

sortArray.sort(function(a, b) {
  if (a.data.name < b.data.name) return -1;
  if (a.data.name > b.data.name) return 1;
  return a.idx - b.idx
});

var answer = sortArray.map(function(val){
    return val.data
});


因为数组包含引用类型objet,所以可以在sort函数中确定元素的索引。所以我们在排序前后都避免使用地图。

1
2
3
4
5
sortArray.sort((function(a, b) {
  if (a.name < b.name) return -1;
  if (a.name > b.name) return 1;
  return this.indexOf(a) - this.indexOf(b);
}).bind(sortArray));


向数组添加额外属性:order

1
2
3
4
5
6
var array = [
    { name:"border-color", value:"#CCCCCC", order: 1 },
    { name:"color", value:"#FFFFFF", order: 2 },
    { name:"background-color", value:"rgb(0, 0, 0)", order: 3 },
    { name:"background-color", value:"rgba(0, 0, 0, .5)", order: 4 }
];

如果名称相等,则将排序函数更改为按顺序排序:

1
2
3
4
5
6
7
array.sort(function(a, b) {
    if (a.name < b.name) return -1;
    if (a.name > b.name) return 1;
    if (a.name == b.name) {
        if(a.order > b.order) return -1; else return 1;
    }
});

请注意,订单返回的符号必须根据您希望它的排序是递增还是递减进行调整(这里,我假设您是从最大到最小排序,所以返回具有较小顺序的排序)。