资讯动态

中文列表怎么排序?Intl.Collator、数字编号与同名记录的处理

发布时间:2026/9/29 22:43:45 来源:尧图企业网站定制
同一份列表为什么“项目10”跑到了“项目2”前面把比较函数改成中文排序后两个同名条目的先后位置又为什么会变这两个问题需要分别处理名称怎样比较以及名称比较相等时记录怎样排。给列表加一行sort()并不等于把排序规则定义完整。本文面向需要处理中文列表的 JavaScript 开发者使用自造数据演示排序规则不涉及真实用户数据或具体产品源码。内容及配图使用 AI 辅助示例代码经过独立运行核验。1. 先说清楚你想要哪一种“顺序”下面四个需求看起来都叫排序实际规则不同需求要先决定的规则中文名称便于查找拼音、笔画还是业务自定顺序项目1、项目2、项目10编号中的数字是否按数值比较两条记录名称相同保留输入顺序还是用稳定的唯一 ID 决定名称缺失或只含空格放到末尾、放到开头还是拒绝这类数据默认的Array.prototype.sort()会把元素转换为字符串按 UTF-16 码元顺序比较它不会主动推断中文拼音规则。sort()还会改变被调用的数组所以想保留原数组顺序可以先复制再排序。参见 MDNArray.prototype.sort()。2. 让 Intl.Collator 负责名称比较Intl.Collator提供与语言相关的字符串比较。它的compare(a, b)返回负数、零或正数判断方向时看符号即可不要把返回值写死为-1或1。参见 MDNIntl.Collator。constnameOrdernewIntl.Collator(zh-CN-u-co-pinyin,{usage:sort,numeric:true,sensitivity:variant});constlabels[项目10,项目2,项目1];constorderedLabels[...labels].sort(nameOrder.compare);console.log(orderedLabels);// 本次环境[项目1, 项目2, 项目10]console.log(nameOrder.resolvedOptions());这组配置提出三个明确要求申请中文拼音排序把数字片段按数值比较保留较细的字符差别。它并不是适合所有业务的默认答案。例如numeric: true很适合“项目2/项目10”这种编号却不是版本号解析器。对于v1.2.0、v1.2.0-beta应先定义版本语义不要仅凭几个样例看起来顺眼就推断完整版本排序也正确。还要区分usage: sort与usage: search本文使用前者。后者用于按完整字符串进行匹配判断不应拿其非零结果做顺序排序也不是子串搜索接口。选项含义可查 MDNIntl.Collator 构造函数。配置会经过运行环境解析实际采用情况可以用resolvedOptions()观察。本文环境里中文请求的collation显示为default不要只看到这个字样就断言“没按中文排”也不要把传入参数当作跨环境验证结果。应结合实际 locale、选项和样例核对。参见 MDNresolvedOptions()。3. 处理真实列表时还缺两层规则设想一个通用项目列表同名记录允许存在暂未命名的记录也需要保留。这里选择如下规则字符串名称先去掉首尾空格非字符串、缺失值和空白名称按“未命名”处理。有名称的记录在前同组按nameOrder比较。名称比较相等时用唯一 ID 排序避免仅因接口返回顺序不同就交换位置。图本文示例的三层比较规则。这只是本文的业务约定。若非字符串代表数据错误你可以改成校验失败不必照搬“按未命名处理”。ID 在这里约定为唯一、非空的 ASCII 字符串数据进入函数前应满足这一条件。functiontextKey(value){returntypeofvaluestring?value.trim():;}functioncompareId(a,b){// ID 仅作最后一层确定次序不按中文名称规则比较。returnab?-1:ab?1:0;}functioncomparePrepared(a,b){constemptyAa.key;constemptyBb.key;if(emptyA!emptyB)returnemptyA?1:-1;returnnameOrder.compare(a.key,b.key)||compareId(a.row.id,b.row.id);}functionorderRows(rows){returnrows.map(row({row,key:textKey(row.name)})).sort(comparePrepared).map(itemitem.row);}constrecords[{id:r4,name:项目10},{id:r3,name:项目2},{id:r2,name:项目2},{id:r5,name: },{id:r1,name:项目1}];console.log(orderRows(records).map(rowrow.id));// 本次环境[r1, r2, r3, r4, r5]这里提前为每条记录计算名称键比较时复用同一个 Collator。函数没有改变输入数组顺序也没有改写对象属性返回的是新数组里面仍是原来的对象引用并不是深拷贝。“比较相等”同样不表示“同一条数据”。中文规则、数字规则或其他配置可能使不同字符串比较为零。不能因此合并联系人、覆盖记录或拿这个结果代替账号 ID 判断。如果你希望相等时保持原输入顺序可以不加 ID 这一层现代标准要求稳定排序。但输入顺序本来就会变化时稳定排序并不能替你统一每次刷新后的次序。应按产品需求选择。参见 MDN排序稳定性。4. 不只验证“排出来看着还行”下面的验证代码接在前两个代码块后可以在 Node.js 中运行。它检查数字顺序、同名记录、空名称、输入保留以及比较函数的自反性、反对称性和传递性。这里的数学性质检查只覆盖列出的样本集合。constassertrequire(node:assert/strict);constidsrowsrows.map(rowrow.id);constbeforeJSON.stringify(records);assert.deepEqual(orderedLabels,[项目1,项目2,项目10]);assert.deepEqual(ids(orderRows(records)),[r1,r2,r3,r4,r5]);assert.equal(JSON.stringify(records),before);assert.notEqual(orderRows(records),records);assert.equal(orderRows(records)[0],records[4]);assert.deepEqual(ids(orderRows([...records].reverse())),ids(orderRows(records)));assert.deepEqual(ids(orderRows(orderRows(records))),ids(orderRows(records)));assert.deepEqual(orderRows([]),[]);assert.deepEqual(ids(orderRows([{id:b,name:null},{id:a,name: },{id:c,name: 项目1 }])),[c,a,b]);assert.equal(textKey(123),);assert.deepEqual([张禾,王宁,李乔,陈安].sort(nameOrder.compare),[陈安,李乔,王宁,张禾]);constsample[...records,{id:r6,name:项目02},{id:r7,name:陈安},{id:r8,name:null},{id:r9,name: 项目1 }].map(row({row,key:textKey(row.name)}));for(constaofsample){assert.equal(comparePrepared(a,a),0);for(constbofsample){constabMath.sign(comparePrepared(a,b));constbaMath.sign(comparePrepared(b,a));assert.ok(ab-ba);for(constcofsample){if(comparePrepared(a,b)0comparePrepared(b,c)0){assert.ok(comparePrepared(a,c)0);}}}}console.log(示例断言通过);本次核验环境为Node.js v24.19.0、ICU 78.3。实际运行的是本文三个代码块全部断言通过没有据此宣称浏览器、数据库或 App 真机测试已经完成。这些中文名字的期望顺序是本轮样例用于发现配置和环境变化不是“所有中文姓名都能正确辨音”的保证。遇到多音姓氏、人工指定读音、企业简称等要求建议把经确认的排序字段作为业务数据维护。Intl.Collator返回比较关系不会替你返回一份姓名拼音表。5. 分页、跨端一致性要另外设计如果接口只返回第 1 页的 20 条数据浏览器重排这 20 条只能得到这一页内部的顺序。第 2 页里本应更靠前的记录不会因此自动挪过来。需要全量有序分页时应让负责分页的一端先完成统一排序并明确同名记录的最后比较字段。对前后端结果必须一致的系统建议同时记录排序策略、运行环境和代表性样例而不只记录一段 locale 字符串。语言排序依赖相应数据与规则规则也可能随版本演进ICU 文档对不同语言、用途和排序约定的差异有专门说明ICUCollation。验收时可以直接问三个具体问题空名称放哪同名数据靠什么分先后分页发生在排序之前还是之后。把这三件事说清楚往往比继续给比较函数叠加选项更有帮助。实际接入时先明确数据约束和分页位置再用上述边界样本验证比较规则。本文示例没有实现输入校验或服务端分页这两部分仍需结合具体系统补充。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑