Javascript排序函数错误地更改元素';阵列中的位置
我在AngularJS应用程序中使用数组排序功能。它使用变量Javascript排序函数错误地更改元素';阵列中的位置,javascript,arrays,sorting,Javascript,Arrays,Sorting,我在AngularJS应用程序中使用数组排序功能。它使用变量direction,来确定是以升序(direction===-1)还是降序(direction===1)的方式对数据进行排序 出了什么问题:有时,当我进行排序时,数组中应该位于同一位置的元素会返回到不同的位置,而数组中没有任何实际更改 例如,如果我有: var arr = [ {id: 3, name: 'd'}, {id: 2, name: 'b'}, {id: 1, name: 'a'
direction
,来确定是以升序(direction===-1
)还是降序(direction===1
)的方式对数据进行排序
出了什么问题:有时,当我进行排序时,数组中应该位于同一位置的元素会返回到不同的位置,而数组中没有任何实际更改
例如,如果我有:
var arr = [
{id: 3, name: 'd'},
{id: 2, name: 'b'},
{id: 1, name: 'a'},
{id: 2, name: 'c'}
];
我按“id”排序,方向为-1
,返回的名称如您所料为“a,b,c,d”。然后我将再次排序(将方向更改为1
),它将反转方向。但是如果我再次对它排序(使用方向==-1
),它将返回“a,c,b,d”的顺序
这是一个简化的例子;事实上,这远比这不可预测
我有一种感觉,在我的分类中,我没有正确地使用方向。见下文:
this.sortData = function (data, type, direction) {
return data.sort(sortFunct);
function sortFunct(a, b) {
var numberTypes = ['Thread', 'Job', 'FolderCount', 'MessageCount', 'EmailCount', 'CalendarCount', 'TaskCount', 'OtherCount', 'JobId', 'BatchId', 'ItemsTotal', 'ItemsRemaining', 'ItemsFailed', 'Size', 'progress', 'PercentComplete'];
var stringTypes = ['Level', 'StatusMessage', 'Author', 'ItemStatus', 'JobStatus', 'SourceMailbox', 'TargetMailbox', 'Subject', 'Folder', 'MessageClass', 'StatusMessage', 'Path', 'Owner1',];
if (numberTypes.indexOf(type) !== -1) {
return direction * (a[type] - b[type]);
} else if (stringTypes.indexOf(type) !== -1) {
if (!a[type]) {
return 1;
} else if (!b[type]) {
return -1;
} else {
return a[type].localeCompare(b[type]) * direction;
}
} else if (type === 'DiscoveryDate' || type === 'ReceivedDate' || type === 'Timestamp') {
if (a[type] > b[type]) {
return direction * 1;
} else if (a[type] < b[type]) {
return direction * -1;
} else {
return 0;
}
} else {
return direction * (a[type] - b[type]);
}
} // End sortFunct
};
this.sortData=函数(数据、类型、方向){
返回data.sort(sortFunct);
函数排序功能(a,b){
var numberTypes=['Thread','Job','FolderCount','MessageCount','EmailCount','CalendarCount','TaskCount','OtherCount','JobId','BatchId','ItemsTotal','ItemsRemaining','ItemsFailed','Size','progress','PercentComplete'];
var stringTypes=['Level','StatusMessage','Author','ItemStatus','JobStatus','SourceMailbox','TargetMailbox','Subject','Folder','MessageClass','StatusMessage','Path','Owner1',];
if(numberTypes.indexOf(type)!=-1){
返回方向*(a[类型]-b[类型];
}else if(stringTypes.indexOf(type)!=-1){
如果(!a[type]){
返回1;
}如果(!b[类型]),则为else{
返回-1;
}否则{
返回a[type].localeCompare(b[type])*方向;
}
}else if(type=='DiscoveryDate'| | type=='ReceivedDate'| | type=='Timestamp'){
如果(a[type]>b[type]){
返回方向*1;
}如果(a[type]
ECMAScript不要求排序稳定()。此外,即使排序是稳定的,也不能期望代码知道何时应该反转相同的记录(2和2),何时不应该反转。为了能够做到这一点,您不能从比较器返回0
——也就是说,在平局的情况下,您需要一个辅助键来帮助消除顺序的歧义。如果想不出更好的方法,可以给每个对象排序。“sort()方法对数组中的元素进行排序并返回数组。排序不一定是稳定的。”
见:
而且:
“HTH,用于.sort()
的ECMAScript规范不要求它是稳定的,因此自定义排序函数所说的相同元素(例如,返回值0
)彼此之间的顺序将没有保证,事实上,它们最终的顺序可能会受到排序之前的顺序的影响
如果您想要一致的排序,那么您永远不需要从自定义排序函数返回0
,除非这两个项完全相同,您永远无法分辨哪个是哪个
当主键相同时,需要测试一个辅助键并返回比较结果。如果二级密钥相同,则比较三级密钥,以此类推,直到您认为值得使用为止
这种二次比较可以使排序保持稳定,这样无论您以前使用的是什么顺序,排序都将始终以可预测的顺序进行
我还看到过一些排序方案,它们创建一个唯一的键并将其分配给每个对象,并将其用作第二个或第三个键,从而确保如果您关心的键是相同的,那么您可以比较唯一的键并始终具有一致的稳定排序
下面是一个方案示例,如果比较字段(本例中的年龄具有相同的值)保持原始顺序。为了知道原始顺序是什么,它使用标识原始顺序的origOrder
属性标记每个对象
var数据=[
{姓名:“艾米”,年龄:13},
{姓名:“安妮”,年龄:13},
{姓名:“约翰”,年龄:11},
{姓名:“杰克”,年龄:12},
{姓名:“Ted”,年龄:11},
{姓名:“爱丽丝”,年龄:12}
];
//按原始顺序标记每个对象
data.forEach(函数(项、索引){
item.origOrder=索引;
});
数据排序(函数(a,b){
var diff=a.年龄-b.年龄;
如果(差异!==0){
返回差;
}否则{
返回a.origOrder-b.origOrder;
}
});
//在代码段中显示结果
document.write(JSON.stringify(data))代码>有趣,我不知道要在这里搜索的正确术语。您认为返回a
和b
的原始索引,然后通过辅助键与之进行比较,会使排序更稳定吗?不确定“返回原始索引”是什么意思?从何处返回?我的意思是,拥有一个真正独特的领域是一件大事;如果这是未修改的数组索引,那很好,但必须事先将其放在对象上,以便比较器可以访问它。我确实有一个唯一的ID字段,但我看不出在该字段上进行比较会如何影响数组排序的稳定性。我的意思是数组中元素的原始索引;如果比较结果为===0,且a在数组中的原始索引低于b,则返回1,否则返回-1。在另一个an的注释中询问此问题