基于多属性维度取最大值:Underscore.js结果不符预期的问题
问题分析与修正方案
你的问题出在_.max的迭代函数逻辑上,现在的写法parseInt(obj.Points) && parseFloat(obj.Rating)在JavaScript里是逻辑与运算,它会返回最后一个为真的表达式值——也就是说,你实际是在用Rating字段单独做比较,Kay的Rating是2.0,是三个里面最大的,所以返回了Kay,这和你想要的「先比Points,Points相同再比Rating」的优先级逻辑完全不符。
要实现你期望的结果(选中Points最高,且Points相同时Rating最高的Micheal),可以用两种方式修正:
方法一:构造复合优先级的比较值
把Points放大到足够大的倍数,加上Rating,确保Points的权重远高于Rating,这样比较复合值就能实现优先级排序:
var maxObject = _.max(data, function(obj){ // 用*10确保Points的优先级高于Rating(如果Rating是多位小数,可以调大倍数,比如*100) return parseInt(obj.Points, 10) * 10 + parseFloat(obj.Rating); }); console.log(maxObject.Person); // 输出 "Micheal"
解释:转换后三个对象的比较值分别是3*10+1.4=31.4、1*10+2.0=12.0、3*10+1.8=31.8,最大的31.8对应Micheal,所以能得到正确结果。
方法二:用排序实现多条件筛选
如果Rating的小数位数不确定,或者想要更直观的多条件控制,可以先按优先级排序,再取第一个元素:
// 按Points降序、Rating降序排列(通过取反实现默认升序方法的降序效果) var sortedList = _.sortBy(data, function(obj) { return [-parseInt(obj.Points, 10), -parseFloat(obj.Rating)]; }); var maxObject = sortedList[0]; console.log(maxObject.Person); // 输出 "Micheal"
解释:_.sortBy默认是升序排序,对数值取反后,原本大的数会变成更小的负数,排在前面,这样就实现了先按Points从高到低排,Points相同的再按Rating从高到低排,第一个元素就是你要的目标对象。
小提示
转换字符串为数值时,记得给parseInt加上第二个参数10(指定十进制解析),避免遇到以0开头的字符串时被误解析为八进制。
内容的提问来源于stack exchange,提问作者Kerberos
相关产品推荐
相关产品推荐

