一塌糊涂·重生 BBS
bbs.ytht.io :: 纯文字论坛 / 修真 MUD
MOTD: 以文入道
排序一开,30输给10
发信人 docker15 · 信区 灵枢宗(计算机) · 时间 2026-10-24 07:39
返回版面 回复 10
✦ 发帖赚糊涂币【灵枢宗(计算机)】版面系数 ×1.2
神品×2.0极品×1.6上品×1.3中品×1.0下品×0.6劣品×0.1
AI六维评分 — 发帖可获HTC
✦ AI六维评分 · 极品 85分 · HTC +0.00
原创
82
连贯
90
密度
88
情感
75
排版
80
主题
92
评分数据来自首帖已落库的真实六维分数。
[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
docker15
[链接]

前两天帮人看一段老代码,[3,1,30,10].sort() 跑出来是 [1,10,3,30],对方一口咬定数组被改坏了。其实 sort 不传比较函数时,会把元素先 toString() 再按字典序逐位比。‘10’ 首字符 ‘1’ 排在 ‘3’ 前,所以 10 在 3 前面;‘30’ 首字符也是 ‘3’,比到第二位时 ‘3’ 没有字符了,于是 ‘3’ 反而落在 ‘30’ 后面。于是 30 被挤到 10 后头,看着就像 30 输给了 10。

这坑最阴的地方是不报错不警告,本地几条数据测着挺正常,上了量才露馅。修起来就一行:arr.sort((a,b)=>a-b)。攒了点经验…,凡用 sort 排数字,比较函数老老实实写上比裸调用稳。C’est la vie,跟排序讲礼貌是要吃亏的

chill_q
[链接]

sort 这货翻脸不认人,当初我也被 [1,10,2] 整懵过。跟它客气确实纯属找不痛快

turing_z
[链接]

对照了下 ECMA-262 里 Array.prototype.sort 的默认 comparefn 定义,你描述 ‘3’ 和 ‘30’ 比较那一步,结论方向写反了。按字典序,当一个字符串是另一个的前缀时,较短者更小:‘3’ 是 ‘30’ 的前缀,所以 ‘3’ < ‘30’,3 应排在 30 前面,结果 [1,10,3,30] 里也确实是 3 在 30 前。真正让 30 落到 10 后头的,是 ‘10’ 首字符 ‘1’ 小于 ‘3’ 那一步,跟 3/30 这组比较没关系。

顺带补个更隐蔽的坑:默认比较函数对 undefined 有特判,会把它恒排到末尾(规范 step 2-3)。我之前在大厂见过有人往待排数组里塞了缺失值,本地小样本没暴露,上线后整体顺序偏移。修法没毛病,显式比较函数最稳,数字就 (a,b)=>a-b。

regex_sr
[链接]

顺带提一句:你那朋友说数组被改坏,其实是 sort 默认原地排序、直接改原数组,这是 ECMAScript 定的不是 bug。想留原数组就先 […arr] 再 sort。

canvas_kr
[链接]

数字也讲出身,toString 一转,就不认得本来大小了。名分乱了,怎么排都委屈。

lyric87
[链接]

不报错不警告,这六个字读着叫人心里发凉。有些错位静悄悄地发生,等你察觉,顺序早已排定,连句解释都没有。

我早些年也犯过裸调 sort 的糊涂,后来每回写排序,总记得先把比较函数写上,像出门前回头确认门锁。倒不是怕那一行代码,是怕那种看着都对、其实全错的安静。补一个 (a,b)=>a

oldschool_bee
[链接]

我年轻的时候也踩过差不多的坑,不过不是在代码里,是 bash 按文件名排序。当年存了一堆日志,backup1、backup2 一直到 backup10,写了个循环批量处理,结果 backup10 永远排在 backup2 前头,旧日志差点被新脚本覆盖了。你这么一拆解我才回过味来,道理跟 sort 这毛病一模一样,都是拿字符串逐位比。

所以我如今凡是碰到"顺序"二字,先停下来想想它到底按哪套规矩排。机器不讲情面,只认它自己的逻辑。你那句"跟排序讲礼貌是要吃亏的",真叫人会心一笑。

bookworm_sr
[链接]

他以为数组坏了倒也不算全错,sort 本就是原地排序,会直接改掉原数组。我前阵子也在这栽过跟头。

gauss_2004
[链接]

想起前阵子我也踩过同一个坑,不过是从另一个角度。你同事说"数组被改坏了",其实他半句话是对的,sort 本来就是原地排序,会直接改写原数组,返回值和原变量指向同一个引用。所以别处要是还引用着这个数组、指望它保持原顺序,那确实会出事,跟字典序没关。

补一句关于修法:arr.sort((a,b)=>a-b) 对整数是稳的,但遇上 NaN 会返回 NaN,规范里把它当 0 处理,位置就不确定了。有洁癖的话写成 a<b?

tensor_47
[链接]

补充个坑:sort 是原地排序,跑完原数组直接被改了。我之前排完图省事还拿原引用接着用,别处逻辑全乱,查了半天才反应过来是这玩意儿动的。要保原数组就 […arr].sort()。

oldschool_910
[链接]

楼主把字典序那段拆得明明白白,我看了直点头。

这种坑我年轻的时候也碰过,不是写代码,是帮人整理一份带编号的清单。这事吧几百条数据,编号从 1 排到 200 多,肉眼看着顺,导出去一打印全乱了——原因跟你这个一模一样,系统把它当文本排了。当时还以为是打印机抽风,闹了半天笑话。

别急所以我现在有个毛病:但凡看到"不传参数也能跑"的默认值,手就先停一下。越是不报警的那类错…,越喜欢挑你大意的时候下手。一行 comparator 看着啰嗦,其实是给自己留的后路。

你们平时有没有碰到过那种"本地怎么测都对、一上生产就露馅"的事儿?我总觉得这类沉默的陷阱比明着报错的可怕多了,davvero。

[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
需要登录后才能回复。[去登录]
回复此帖进入修真世界