游戏开发中,多字段的排序问题

问题如下,

一个奖励列表,要求先按 "未领取>已领取",再按 "粮食>铁矿>石头>木头",再按 "数量降序",最后按 "id升序" 进行排序,问 sort 的compare方法怎么写? 

let rewardList = [
    { id: 1, num: 100, name: "木头", hasReceived: true },
    { id: 2, num: 789, name: "石头", hasReceived: false },
    { id: 3, num: 555, name: "铁矿", hasReceived: false },
    { id: 4, num: 555, name: "石头", hasReceived: false },
    { id: 5, num: 100, name: "石头", hasReceived: true },
    { id: 6, num: 20, name: "粮食", hasReceived: true }
];

rewardList.sort((a, b) => {
    //?
});

先回顾一下sort compare方法的基本规则(不同语言都差不多,这里拿js中ab对象的x字段来说):

    若想要升序排序,可直接返回 a.x - b.x 。比较时,当a.x>b.x, 则差为正,就交换a和b的位置;反之,当a.x<b.x,则差为负,保持a和b的位置不变。

   若想要降序排序,就直接返回 b.x - a.x。

通常,对number类型进行比较排序非常容易,直接做减法即可。如,先按 "num降序排序" 再按 "id升序"排序:

rewardList.sort((a, b) => {
    if (a.num != b.num) {
        return b.num - a.num;
    } else {
        return a.id - b.id; 
    }
});

那对不能直接比较大小的 bool 值,要怎么排序呢?曾经,我一直都是这么干的:

rewardList.sort((a, b) => {
    if (a.isReceived != b.isReceived) { 
        //领取状态不同时,a领取且b未领取时,a排在b前(使其返回一个正值1)。
        return a.isReceived && !b.isReceived ? 1 : -1;
    } else {
        //领取状态相同时,保持位置不变(使其返回一个负值-1)
        return -1;
    }
});

这样也没问题(bool 数据只有两种分组 true 和 false,还比较容易)。

那分组情况较多的 string 类型数据要怎么处理呢?强行写 if else 列出每种情况非常麻烦。

实际上,对于非 number 的数据类型,可以创建临时的排序映射来解决排序问题。如下:

(sting 和 enum 是类似的)

//name,按:粮食 > 铁矿 > 石头 > 木头
let nameSortMap = { "粮食" : 1, "铁矿" : 2, "石头" : 3, "木头" : 4 };
//received,按:true > false
let receivedSortMap = { "true" : 1, "false" : 2 };

rewardList.sort((a, b) => {
    //先按领取状态
    if (a.hasReceived != b.hasReceived) { 
        return receivedSortMap[a.hasReceived.toString()] - receivedSortMap[b.hasReceived.toString()];
    } else {
        //再按名称
        if (a.name != b.name) {
            return nameSortMap[a.name] - nameSortMap[b.name];
        } else {
            //再按数量 降序
            if (a.num != b.num) {
                return b.num - a.num;
            } else {
                //最后按id 升序
                return a.id - b.id;
            }
        }
    }
});

结果如下:

问题到此算是解决了。那是否还可以继续优化呢?上面的 if else 可是嵌套了一层一层的啊。。

实际上,在范围可控的情况下,可以为每个字段赋予一个权重,各字段分别乘以各自的权重,最终得到一个值,对此值进行排序。这样就消除了嵌套的 if else。注意,它只适用于范围可控的情况。

猜你喜欢

转载自blog.csdn.net/NRatel/article/details/88378466
今日推荐