lists:sort/2的问题

-define(true, true).
-define(false, false).

%% 联盟的积分
-record(league_score, {
            score = 0,         % 当前累计的积分
            unixtime = 0,      % 最后一次获取积分时的时间戳(积分排名时,如果累计积分相同,则此字段较小者获胜)
            rank = 0           % 积分排名(用于显示)
            }).


foo() ->
    ScoreInfoList = [{105,{league_score,12,1448203750173,0}},
                           {108,{league_score,20,1448203897417,0}}],

    SortF = fun({LeagueId_A, LeagueScore_A}, {LeagueId_B, LeagueScore_B}) ->
                case LeagueScore_A#league_score.score > LeagueScore_B#league_score.score of
                    ?true -> ?true;
                    ?false ->
                           ?false
                end
            end,

    lists:sort(SortF, ScoreInfoList).


bar() ->
    ScoreInfoList = [{105,{league_score,12,1448203750173,0}},
                           {108,{league_score,20,1448203897417,0}}],

    SortF = fun({LeagueId_A, LeagueScore_A}, {LeagueId_B, LeagueScore_B}) ->
                case LeagueScore_A#league_score.score > LeagueScore_B#league_score.score of
                    ?true -> ?true;
                    ?false ->
                        % *****
                        case LeagueScore_A#league_score.unixtime < LeagueScore_B#league_score.unixtime of
                            ?true ->
                                ?true;
                            ?false ->
                                LeagueId_A > LeagueId_B
                        end
                end
            end,

    lists:sort(SortF, ScoreInfoList).



如上, foo函数和bar函数几乎是一样的,除了bar函数中标注*****的部分不一样之外,其他都一样。
本以为两个函数返回的结果应该是一样的, 但实际上完全相反:

50> b:foo().
[{108,{league_score,20,1448203897417,0}},
{105,{league_score,12,1448203750173,0}}]
51> b:bar().
[{105,{league_score,12,1448203750173,0}},
{108,{league_score,20,1448203897417,0}}]
52>


这个一开始还以为是lists:sort的实现存在bug, 再想想, 应该不是, 而是lists:sort排序处理的实现和自己原先所认为的不一样。
原以为,SortF的写法足以可以告知lists:sort这样的事实(排序依据): 积分大者排在前。
但实际上lists:sort并没有这么“智能”,从
这个例子可以推测出lists:sort是严格走SorF的判断处理流程的:
      首先拿A的score和B的比较, 发现LeagueScore_A#league_score.score > LeagueScore_B#league_score.score并不成立,于是执行false分支,
于是接着拿A的unixtime和B的对比, 发现LeagueScore_A#league_score.unixtime < LeagueScore_B#league_score.unixtime 成立,于是SortF的结果是true,
从而A排在B前, 所以bar()的结果就是如上所示。


须留意!

此外, bar函数中的SortF的判断逻辑本身是不正确的,判断时没有细化分为大于,小于, 以及等于的三种情况。 正确的判断应该是:

if
    LeagueScore_A#league_score.score > LeagueScore_B#league_score.score ->
        ?true;
    LeagueScore_A#league_score.score < LeagueScore_B#league_score.score ->
        ?false;
    ?true ->
        if
            LeagueScore_A#league_score.unixtime < LeagueScore_B#league_score.unixtime ->
                ?true;
            LeagueScore_A#league_score.unixtime > LeagueScore_B#league_score.unixtime ->
                ?false;
            ?true ->
                LeagueId_A > LeagueId_B
        end
end

 

以上,脑袋迷糊的时候容易犯错,同样须留意!






 

posted @ 2015-11-23 00:23  kamfon  阅读(336)  评论(0编辑  收藏  举报