-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
以上,脑袋迷糊的时候容易犯错,同样须留意!