Javascript 对数组项进行排序并保留相同元素的顺序
假设我有这个数组:Javascript 对数组项进行排序并保留相同元素的顺序,javascript,arrays,sorting,Javascript,Arrays,Sorting,假设我有这个数组: 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)" } ]; 此函数用于按名称对数组进行排序: array.
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)" }
];
此函数用于按名称对数组进行排序:
array.sort(function(a, b) {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
});
或
如何对数组进行排序,使同名项保持其相对顺序?我不想硬编码任何东西。理论上,在排序之前,您可以跟踪其在数组中的索引,并在排序时将其考虑在内
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
});
var sortArray=yourarray.map(函数(数据,idx){
返回{idx:idx,data:data}
})
sortArray.sort(函数(a,b){
if(a.data.nameb.data.name)返回1;
返回a.idx-b.idx
});
var answer=sortArray.map(函数(val){
返回val.data
});
向数组添加一个额外属性:order
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 }
];
然后,如果名称相等,则将“排序”函数更改为“按顺序排序”:
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;
}
});
array.sort(函数(a,b){
如果(a.nameb.name)返回1;
如果(a.name==b.name){
如果(a.订单>b.订单)返回-1;否则返回1;
}
});
请注意,订单的返回符号必须根据您希望其排序是递增还是递减进行调整(这里,我假设您是从最大到最小排序,因此返回顺序较小的一个)。因为数组包含引用类型objet,元素的索引可以在sort函数中确定。因此,我们避免在排序之前和之后使用映射
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));
sortArray.sort((函数a,b){
如果(a.nameb.name)返回1;
返回此.indexOf(a)-此.indexOf(b);
}).bind(sortArray));
这一点最近有所改变<代码>数组#排序稳定,这意味着具有相同<代码>名称的两个条目之间的相对位置将与排序数组之前相同:
22.1.3.27Array.prototype.sort(比较)
此数组的元素已排序排序必须稳定(即,比较相等的元素必须保持其原始顺序)
(我的重点)
因此,在您的例子中,{name:“background color”,value:“rgb(0,0,0)”}
和{name:“background color”,value:“rgba(0,0,0,5)”}
的顺序将保持不变,因为它们的比较结果相同
在ES2019之前,排序不需要是稳定的,因此它们可以颠倒顺序-或者不颠倒顺序,这取决于实现。在ES6中,如果由于浏览器环境或transpiler插件设置而无法保证排序顺序(在理想情况下,这不应该是问题),非常惯用/快速的方法可以是:
values
.map((v, i) => ([v,i]))
.sort(([v1,i1], [v2,i2])=> (
(v1==v2) ? (i2-i1) : (v2-v1)
)).map(([v,i])=>v); // or above flipped
这种方法的缺点是它不如合并排序有效,但它非常接近,因为大多数浏览器实现都将其用于Array.prototype.sort
内部或甚至更优化(在这种情况下,应该是O(2n)+O(nlogn))
优点是它非常方便且易于阅读——在返回语句之后,不需要使用
else
。如果(a.order>b.order)返回-1,您只需执行;返回1代码>。您还可以删除包装if(a.name==b.name){}
语句,该语句在执行时始终为true(因为它既不是
也不是你从哪里得到idx
的?很好,修复了映射上参数的名称function@noveyak由于数组包含引用类型objet,元素的索引可以在排序函数中确定。因此,我们避免在排序之前和之后使用映射。这不是很慢,因为它s每次都要找到索引吗?抱歉投了反对票:这不好,因为this.indexOf(a)和this.indexOf(b)排序时会发生变化。排序前需要记住初始索引使用@IONESHO添加,当数组中有多个值相同的项时,indexOf函数也会返回错误的索引。有关稳定排序的简短ES6实现,请查看此答案:
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));
values
.map((v, i) => ([v,i]))
.sort(([v1,i1], [v2,i2])=> (
(v1==v2) ? (i2-i1) : (v2-v1)
)).map(([v,i])=>v); // or above flipped