为啥以下 javascript 数组排序决定我的两个排序顺序参数未定义?

Posted

技术标签:

【中文标题】为啥以下 javascript 数组排序决定我的两个排序顺序参数未定义?【英文标题】:Why is the following javascript array sort deciding that two of my sort order parameters are undefined?为什么以下 javascript 数组排序决定我的两个排序顺序参数未定义? 【发布时间】:2018-03-26 14:37:11 【问题描述】:

这是直接从我的代码和控制台日志中复制的。如您所见,它是一个对象数组。我正在尝试根据我在单独对象中定义的排序顺序对对象进行排序。它对 7 个元素中的 5 个进行排序,但看似随意地决定未定义排序对象的两个属性。该对象由我的代码字符串化,并在表示它未定义的行之前写入日志。显然它不是未定义的。那么这里发生了什么?

这个对象定义了我想要使用的排序顺序。

const statSortOrder = 
"4043523819": 0, //impact
"1240592695": 1, //range
"155624089": 2,  //stablility
"943549884": 3,  //handling
"4188031367": 4, //reload speed
"4284893193": 5, //rounds per minute
"3871231066": 6 //magazine
;

此代码应根据此顺序对对象数组进行排序。请注意,我在这里有一些额外的东西来吐出控制台正在发生的事情的详细结果。我将复制结果日志的内容和数组“orderArray”的内容进一步向下。

console.log("STAT SORT ORDER: \n" + JSON.stringify(statSortOrder));
console.log("UNORDERED ARRAY: \n" + JSON.stringify(orderArray));
orderArray.sort((a,b) => 
    if(a.hash && statSortOrder[a.hash.toString()] && b.hash && statSortOrder[b.hash.toString()]) 
        console.log("statSorOrder[a.hash] = " + statSortOrder[a.hash.toString()] + " : statSortOrder[b.hash] = " + statSortOrder[b.hash.toString()]);
        return statSortOrder[a.hash.toString()] - statSortOrder[b.hash.toString()];
     else 
        console.log("statSortOrder = " + JSON.stringify(statSortOrder) + "\n"
        + "No match because a.hash.toString() =  " + a.hash.toString() + " and statSortOrder[a.hash.toString()] = " + statSortOrder[a.hash.toString()] + "\n"
        + " and b.hash.toString() = " + b.hash.toString() + " and statSortOrder[b.hash.toString()] = " + statSortOrder[b.hash.toString()]);
        return -1;
    
);
console.log("ORDER ARRAY: \n" + JSON.stringify(orderArray));

所以这是我在日志中捕获的内容:

2017-10-14T16:31:40.594Z    2628c5d7-b0fd-11e7-8b39-9b4f450e9f47    statSorOrder[a.hash] = 2 : statSortOrder[b.hash] = 3
2017-10-14T16:31:40.594Z    2628c5d7-b0fd-11e7-8b39-9b4f450e9f47    statSorOrder[a.hash] = 3 : statSortOrder[b.hash] = 1
2017-10-14T16:31:40.594Z    2628c5d7-b0fd-11e7-8b39-9b4f450e9f47    statSorOrder[a.hash] = 2 : statSortOrder[b.hash] = 1
2017-10-14T16:31:40.594Z    2628c5d7-b0fd-11e7-8b39-9b4f450e9f47    statSorOrder[a.hash] = 3 : statSortOrder[b.hash] = 6
2017-10-14T16:31:40.594Z    2628c5d7-b0fd-11e7-8b39-9b4f450e9f47    
statSortOrder =

    "155624089": 2,
    "943549884": 3,
    "1240592695": 1,
    "3871231066": 6,
    "4043523819": 0,
    "4188031367": 4,
    "4284893193": 5


No match because a.hash.toString() = 3871231066 and 
statSortOrder[a.hash.toString()] = undefined
and b.hash.toString() = 4043523819 and statSortOrder[b.hash.toString()] = 0
2017-10-14T16:31:40.594Z    2628c5d7-b0fd-11e7-8b39-9b4f450e9f47    
statSortOrder =

    "155624089": 2,
    "943549884": 3,
    "1240592695": 1,
    "3871231066": 6,
    "4043523819": 0,
    "4188031367": 4,
    "4284893193": 5


No match because a.hash.toString() = 4043523819 and 
statSortOrder[a.hash.toString()] = undefined
and b.hash.toString() = 4188031367 and statSortOrder[b.hash.toString()] = 4
2017-10-14T16:31:40.594Z    2628c5d7-b0fd-11e7-8b39-9b4f450e9f47    statSorOrder[a.hash] = 4 : statSortOrder[b.hash] = 5

这是排序操作前后对象数组的内容:

之前:

[

    "entityType": "DestinyStatDefinition",
    "index": 19,
    "icon": "/img/misc/missing_icon_d2.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Stability",
    "ciName": "stability",
    "hash": 155624089,
    "displayProperties": 
        "name": "Stability",
        "icon": "/img/misc/missing_icon_d2.png",
        "description": "How much or little recoil you will experience while firing the weapon.",
        "hasIcon": false
    ,
    "hasIcon": false,
    "interpolate": false,
    "description": "How much or little recoil you will experience while firing the weapon.",
    "id": 155624089

,

    "entityType": "DestinyStatDefinition",
    "index": 23,
    "icon": "/img/misc/missing_icon_d2.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Handling",
    "ciName": "handling",
    "hash": 943549884,
    "displayProperties": 
        "name": "Handling",
        "icon": "/img/misc/missing_icon_d2.png",
        "description": "The speed with which the weapon can be readied and aimed.",
        "hasIcon": false
    ,
    "hasIcon": false,
    "interpolate": false,
    "description": "The speed with which the weapon can be readied and aimed.",
    "id": 943549884

,

    "entityType": "DestinyStatDefinition",
    "index": 15,
    "icon": "/img/misc/missing_icon_d2.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Range",
    "ciName": "range",
    "hash": 1240592695,
    "displayProperties": 
        "name": "Range",
        "icon": "/img/misc/missing_icon_d2.png",
        "description": "Increases the effective range of this weapon.",
        "hasIcon": false
    ,
    "hasIcon": false,
    "interpolate": false,
    "description": "Increases the effective range of this weapon.",
    "id": 1240592695

,

    "entityType": "DestinyStatDefinition",
    "index": 21,
    "icon": "/img/theme/destiny/icons/icon_magazineSize.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Magazine",
    "ciName": "magazine",
    "hash": 3871231066,
    "displayProperties": 
        "name": "Magazine",
        "icon": "/img/theme/destiny/icons/icon_magazineSize.png",
        "description": "The number of shots which can be fired before reloading.",
        "hasIcon": true
    ,
    "hasIcon": true,
    "interpolate": false,
    "description": "The number of shots which can be fired before reloading.",
    "id": -423736230

,

    "entityType": "DestinyStatDefinition",
    "index": 14,
    "icon": "/img/misc/missing_icon_d2.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Impact",
    "ciName": "impact",
    "hash": 4043523819,
    "displayProperties": 
        "name": "Impact",
        "icon": "/img/misc/missing_icon_d2.png",
        "description": "Increases the damage inflicted by each round.",
        "hasIcon": false
    ,
    "hasIcon": false,
    "interpolate": false,
    "description": "Increases the damage inflicted by each round.",
    "id": -251443477

,

    "entityType": "DestinyStatDefinition",
    "index": 24,
    "icon": "/img/misc/missing_icon_d2.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Reload Speed",
    "ciName": "reload speed",
    "hash": 4188031367,
    "displayProperties": 
        "name": "Reload Speed",
        "icon": "/img/misc/missing_icon_d2.png",
        "description": "The time it takes to reload this weapon.",
        "hasIcon": false
    ,
    "hasIcon": false,
    "interpolate": false,
    "description": "The time it takes to reload this weapon.",
    "id": -106935929

,

    "entityType": "DestinyStatDefinition",
    "index": 13,
    "icon": "/img/misc/missing_icon_d2.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Rounds Per Minute",
    "ciName": "rounds per minute",
    "hash": 4284893193,
    "displayProperties": 
        "name": "Rounds Per Minute",
        "icon": "/img/misc/missing_icon_d2.png",
        "description": "The number of shots per minute this weapon can fire.",
        "hasIcon": false
    ,
    "hasIcon": false,
    "interpolate": false,
    "description": "The number of shots per minute this weapon can fire.",
    "id": -10074103

]

之后:

[
    "entityType": "DestinyStatDefinition",
    "index": 15,
    "icon": "/img/misc/missing_icon_d2.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Range",
    "ciName": "range",
    "hash": 1240592695,
    "displayProperties": 
      "name": "Range",
      "icon": "/img/misc/missing_icon_d2.png",
      "description": "Increases the effective range of this weapon.",
      "hasIcon": false
    ,
    "hasIcon": false,
    "interpolate": false,
    "description": "Increases the effective range of this weapon.",
    "id": 1240592695
  ,
  
    "entityType": "DestinyStatDefinition",
    "index": 19,
    "icon": "/img/misc/missing_icon_d2.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Stability",
    "ciName": "stability",
    "hash": 155624089,
    "displayProperties": 
      "name": "Stability",
      "icon": "/img/misc/missing_icon_d2.png",
      "description": "How much or little recoil you will experience while firing the weapon.",
      "hasIcon": false
    ,
    "hasIcon": false,
    "interpolate": false,
    "description": "How much or little recoil you will experience while firing the weapon.",
    "id": 155624089
  ,
  
    "entityType": "DestinyStatDefinition",
    "index": 23,
    "icon": "/img/misc/missing_icon_d2.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Handling",
    "ciName": "handling",
    "hash": 943549884,
    "displayProperties": 
      "name": "Handling",
      "icon": "/img/misc/missing_icon_d2.png",
      "description": "The speed with which the weapon can be readied and aimed.",
      "hasIcon": false
    ,
    "hasIcon": false,
    "interpolate": false,
    "description": "The speed with which the weapon can be readied and aimed.",
    "id": 943549884
  ,
  
    "entityType": "DestinyStatDefinition",
    "index": 21,
    "icon": "/img/theme/destiny/icons/icon_magazineSize.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Magazine",
    "ciName": "magazine",
    "hash": 3871231066,
    "displayProperties": 
      "name": "Magazine",
      "icon": "/img/theme/destiny/icons/icon_magazineSize.png",
      "description": "The number of shots which can be fired before reloading.",
      "hasIcon": true
    ,
    "hasIcon": true,
    "interpolate": false,
    "description": "The number of shots which can be fired before reloading.",
    "id": -423736230
  ,
  
    "entityType": "DestinyStatDefinition",
    "index": 14,
    "icon": "/img/misc/missing_icon_d2.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Impact",
    "ciName": "impact",
    "hash": 4043523819,
    "displayProperties": 
      "name": "Impact",
      "icon": "/img/misc/missing_icon_d2.png",
      "description": "Increases the damage inflicted by each round.",
      "hasIcon": false
    ,
    "hasIcon": false,
    "interpolate": false,
    "description": "Increases the damage inflicted by each round.",
    "id": -251443477
  ,
  
    "entityType": "DestinyStatDefinition",
    "index": 24,
    "icon": "/img/misc/missing_icon_d2.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Reload Speed",
    "ciName": "reload speed",
    "hash": 4188031367,
    "displayProperties": 
      "name": "Reload Speed",
      "icon": "/img/misc/missing_icon_d2.png",
      "description": "The time it takes to reload this weapon.",
      "hasIcon": false
    ,
    "hasIcon": false,
    "interpolate": false,
    "description": "The time it takes to reload this weapon.",
    "id": -106935929
  ,
  
    "entityType": "DestinyStatDefinition",
    "index": 13,
    "icon": "/img/misc/missing_icon_d2.png",
    "hasComputedBlock": false,
    "aggregationType": 2,
    "redacted": false,
    "name": "Rounds Per Minute",
    "ciName": "rounds per minute",
    "hash": 4284893193,
    "displayProperties": 
      "name": "Rounds Per Minute",
      "icon": "/img/misc/missing_icon_d2.png",
      "description": "The number of shots per minute this weapon can fire.",
      "hasIcon": false
    ,
    "hasIcon": false,
    "interpolate": false,
    "description": "The number of shots per minute this weapon can fire.",
    "id": -10074103
  
]

【问题讨论】:

您的日志记录调用有一个错字 - 您有 .toString,而您应该有 .toString()。无论如何都不需要调用.toString(),因为javascript 总是隐含地为[ ] 运算符使用的表达式值做这件事。 另请注意,您在statSortOrder 中测试值的方式意味着当哈希映射到0 时,它的行为就像没有条目一样。您可以使用 in 运算符来避免这种情况,尽管这可能是故意的。 谢谢尖头。我更正了 toString 调用,但我认为结果仍然有效。最初我并没有调用 toString,但它是其中之一,当出现问题时你真的摸不着头脑,你就会开始尝试 anything 你知道的。所以我绝望地添加了 toString,但你的观点很好。 请注意,每个数字属性都不需要.toString() .... 使用obj[number] 会自动将数字转换为字符串,因为对象不能具有数字属性 【参考方案1】:

代替:

if(a.hash && statSortOrder[a.hash.toString()] && b.hash && statSortOrder[b.hash.toString()]) 

...您应该像这样更精确地检查密钥是否存在:

if(a.hash && a.hash.toString() in statSortOrder && b.hash && b.hash.toString() in statSortOrder) 

其次,由于else 部分中的错误,您的输出更加混乱:

" and statSortOrder[a.hash.toString()] = " + statSortOrder[a.hash.toString]

...但是您忘记实际调用 toString 并且应该这样做:

" and statSortOrder[a.hash.toString()] = " + statSortOrder[a.hash.toString()]

【讨论】:

【参考方案2】:

这个

"4043523819": 0, //impact

返回一个虚假值,它会导致您所做的检查出现问题。您可以将排序顺序对象statSortOrder 中的所有值加一。

【讨论】:

... 或做类似(a.hash in statSortOrder) @Pointy,一个简短的版本是直接使用该值,例如return (statSortOrder[a.hash] || defaultValue) - (statSortOrder[b.hash] || defaultValue),并根据需要使用defaultValue 将未散列的值移动到底部或底部。 做到了。非常感谢。

以上是关于为啥以下 javascript 数组排序决定我的两个排序顺序参数未定义?的主要内容,如果未能解决你的问题,请参考以下文章

为啥数字数组,更多数据排序比对象数组更快,Javascript中的数据更少?

当我使用冒泡排序时,为啥我将数组中的最高值作为我的第一个元素?

找出后缀数组的两种算法中哪一种更快,为啥?

为啥函数的参数对象不是 Javascript 中的数组?

JS数组排序,有些位置不懂,帮忙注释哈。为啥从小到大排序?

为啥在我的情况下快速排序总是比冒泡排序慢?