ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

jstips 第 26 期:用 filter + sort 对字符串列表去重并按字母表排序

jstips 第 26 期:用 filter + sort 对字符串列表去重并按字母表排序 教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载本篇文章源自开源仓库 jstips仓库根目录中编号为 26 的 JavaScript 技巧文章原文位于 _posts/en/javascript/2016-01-26-filtering-and-sorting-a-list-of-strings.md。当你在实际项目中拿到一份含大量重复、且顺序混乱的字符串列表例如用户名、标签、配置项名时本文展示的filtersort组合能在一两行代码内完成去重 按字母表排序的双重清洗。读完本文你将掌握基于lastIndexOf的索引比对去重技巧、比较函数驱动的排序写法以及 ES6 箭头函数下的极简等价实现并了解该方案在复杂数据与多语言环境下的边界与替代手段。场景一份需要清洗的 JavaScript 保留关键字列表假设你维护着一份跨版本整理的JavaScript 保留字列表ES5、ES6ECMAScript 2015、ES7 乃至未来提案中的关键字都被粗放地堆在一起。这样一份数据有两个典型问题大量重复do、if、in、for、new、try、var等基础关键字在多个版本中反复出现毫无顺序关键字没有按字母表组织直接交给用户或下游程序都不便于阅读与检索。因此它是一份完美的字符串数组Array测试样本。原始数据如下完整保留原文数据可直接复制运行var keywords [do, if, in, for, new, try, var, case, else, enum, null, this, true, void, with, break, catch, class, const, false, super, throw, while, delete, export, import, return, switch, typeof, default, extends, finally, continue, debugger, function, do, if, in, for, int, new, try, var, byte, case, char, else, enum, goto, long, null, this, true, void, with, break, catch, class, const, false, final, float, short, super, throw, while, delete, double, export, import, native, public, return, static, switch, throws, typeof, boolean, default, extends, finally, package, private, abstract, continue, debugger, function, volatile, interface, protected, transient, implements, instanceof, synchronized, do, if, in, for, let, new, try, var, case, else, enum, eval, null, this, true, void, with, break, catch, class, const, false, super, throw, while, yield, delete, export, import, public, return, static, switch, typeof, default, extends, finally, package, private, continue, debugger, function, arguments, interface, protected, implements, instanceof, do, if, in, for, let, new, try, var, case, else, enum, eval, null, this, true, void, with, await, break, catch, class, const, false, super, throw, while, yield, delete, export, import, public, return, static, switch, typeof, default, extends, finally, package, private, continue, debugger, function, arguments, interface, protected, implements, instanceof];用高阶函数 filter 完成去重lastIndexOf 索引比对我们不想改动原始列表因此使用数组的高阶函数 filter。filter基于我们传入的谓词predicate即一个返回布尔值的函数对每个元素进行判定返回一个全新的过滤后数组原始数组保持不变。去重的核心思路是索引比对对数组中第index个元素keyword调用keywords.lastIndexOf(keyword)得到该值在原始列表中最后一次出现的位置。只有当最后一次出现的位置恰好等于当前遍历位置时才说明当前这个元素就是该值的最后一个副本把它保留下来其余更早出现的重复副本都会被过滤掉。var filteredAndSortedKeywords keywords .filter(function (keyword, index) { return keywords.lastIndexOf(keyword) index; }) .sort(function (a, b) { return a b ? -1 : 1; });用 sort 完成字母表排序比较函数驱动filter只负责去重排序交给 sort。sort接受一个比较函数作为唯一参数比较函数接收两个元素a、b返回负数表示a排在b前面返回正数表示a排在b后面。这里a b ? -1 : 1用字符串的字典序比较结果驱动排序最终得到按字母表升序排列的列表。两点说明上述比较函数对相等的情况返回1而非0。由于去重后的列表内不存在相等元素该写法在实际运行中不会引发排序错误但从严格意义上讲比较函数在相等时应返回0可写成a b ? -1 : a b ? 1 : 0。默认的字典序比较基于各字符的 UTF-16 码点对纯 ASCII 小写字母本例关键字全部为小写恰好等价于字母表顺序若涉及大小写混合或非 ASCII 字符则需要参考后文多语言与边界情况一节的方案。ES6 箭头函数一行更简洁的等价实现原文同时给出了ES6ECMAScript 2015版本使用箭头函数后谓词与比较函数都变得更加精简const filteredAndSortedKeywords keywords .filter((keyword, index) keywords.lastIndexOf(keyword) index) .sort((a, b) a b ? -1 : 1);语义与 ES5 版本完全一致箭头函数省略了function关键字与return的显式书写单表达式函数体自动返回计算结果。运行结果验证在 Node.js 或浏览器控制台直接运行console.log(filteredAndSortedKeywords);得到最终去重并按字母表排序后的 JavaScript 保留字列表共 63 个唯一关键字// [abstract, arguments, await, boolean, break, byte, case, catch, char, class, const, continue, debugger, default, delete, do, double, else, enum, eval, export, extends, false, final, finally, float, for, function, goto, if, implements, import, in, instanceof, int, interface, let, long, native, new, null, package, private, protected, public, return, short, static, super, switch, synchronized, this, throw, throws, transient, true, try, typeof, var, void, volatile, while, with, yield]可以看到do、if、for等跨版本重复的关键字只保留了一份且整个列表已按字母表从abstract到yield有序排列。结合仓库的纵深扩展去重方案的横向对比indexOf、Set 与展开运算符仓库中 _posts/en/javascript/2016-02-06-deduplicate-an-array.md 系统总结了数组去重的多种写法可与本文方案对照理解filter indexOfarr.indexOf(el) i判断当前元素是否为首次出现。与本文lastIndexOf(el) i判断是否为最后一次出现思路对称效果等价二者都只适用于元素按值比较的场景ES2015 的 Set Array.fromArray.from(new Set([1, 1, a, a]))一行完成去重是更简洁的现代写法Set 展开运算符_posts/en/javascript/2017-03-12-3-array-hacks.md 中的第三种 hack 给出了[...new Set([1, 2, 3, 3])]的写法结果同为[1, 2, 3]。需要注意的是对象按引用比较{ a: 1 } { a: 1 }为false因此lastIndexOf/indexOf/Set均无法直接对对象数组去重此时需要借助JSON.stringify序列化后存入哈希表详见上文 deduplicate 文章中的dedup实现。排序的边界带重音字符的多语言字符串本文示例均为纯 ASCII 小写字母直接使用sort即可得到字母表顺序。但仓库中 _posts/en/javascript/2016-01-04-sorting-strings-with-accented-characters.md 指出对[é, a, ú, c]这类非 ASCII 字符排序会得到异常结果如[c, e, á, ú]因为默认sort只按码点工作不遵循具体语言的字母表规则。该文的解决方案同样适用于本文的排序环节// 使用 localeCompare 作为比较函数 [único, árbol, cosas, fútbol].sort(function (a, b) { return a.localeCompare(b); }); // [árbol, cosas, fútbol, único] // 或直接传入 Intl.Collator 的 compare [único, árbol, cosas, fútbol].sort(Intl.Collator().compare);两种方式都支持按语言环境locale定制排序规则。因此如果你的字符串列表包含大小写混合或带重音字符例如多语言国家名、本地化标签应在比较函数中改用localeCompare或Intl.Collator().compare避免出现看起来是排序了、结果却不符合语言习惯的问题。关于 filter 与链式调用的方法论从仓库中的 _posts/en/javascript/2017-06-15-looping-over-arrays.md 可以看到filter的完整签名是filter(current_value, index, array)其语义是基于布尔函数过滤数组元素这正是本文去重所用的核心工具。与forEach不返回新数组不同filter与map、sort一样返回可继续链式调用的数组因此filter(...).sort(...)的流水线写法得以成立这也呼应了仓库中 _posts/en/javascript/2016-01-20-return-objects-to-enable-chaining-of-functions.md 所倡导的链式风格——每一步返回新值让数据变换可读、可复用、不污染原始数据。复杂度与使用注意从代码结构推断从实现结构看filter回调对每个元素都会调用一次lastIndexOf而lastIndexOf本身是一次线性扫描因此该去重方案的整体时间复杂度约为 O(n²)。对于本文 200 余条关键字这种中小规模列表毫无压力若面对数万级以上的大数组可优先考虑Set底层哈希结构或先排序再相邻去重等更高效的手段。filtersort均不修改原始数组keywords变量在流程结束后仍保持原样适合需要保留原始数据的场景。去重依赖值相等判定若列表中大小写混写如Do与do会被视为两个不同元素而不会被去重需要大小写不敏感去重时可先用toLowerCase()归一化再做索引比对。小结本文的核心配方可以概括为一句话filter用lastIndexOf(keyword) index保留每个值的最后一次出现以完成去重sort用字典序比较函数完成字母表排序两者通过链式调用组合成一条不修改原数组的数据清洗流水线ES6 箭头函数可将其压缩为两行。当数据复杂度上升时可参考仓库中 deduplicate 文章 的Set/哈希表方案处理对象或大数组参考 带重音字符排序文章 的localeCompare/Intl.Collator方案处理多语言排序。这套组合拳是日常开发中处理去重 排序类需求最直接的起点。赞分享教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载相关推荐Reth 文档站工程实践:基于 Vocs 的 MDX 文档架构、构建流水线与开发工作流Reth 文档站工程实践:基于 Vocs 的 MDX 文档架构、构建流水线与开发工作流 本文围绕 Reth 仓库中 docs/vocs/CLAUDE.md 这份教程RxJS操作符速查表按字母顺序排列的参考RxJS操作符速查表按字母顺序排列的参考 简介 RxJSReactive Extensions for JavaScript提供了丰富的操作符用于处理异后端pnpm 代理配置空值语义修复HTTP_PROXY 不再触发 ERR_PNPM_INVALID_PROXYpnpm 代理配置空值语义修复 HTTP_PROXY 不再触发 ERR_PNPM_INVALID_PROXY 本篇文章聚焦 pnpm 仓库中一个具体的变更集教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表