如何将句子数组按最大长度合并为完整句子块?递归是否最优?
按最大长度合并完整句子数组的实现方案
我们已经将长字符串通过正则拆分为由完整句子组成的数组,已知单个句子长度不超过设定的maxLength。需要将数组中的句子以空格连接,合并为若干长度不超过maxLength的字符串块,且每个块必须包含完整句子(支持...、?!等特殊句子结尾)。下面给出具体实现方案,并讨论递归是否为最优雅的实现方式。
输入与预期输出示例
// 输入字符串与拆分代码 const input = "This is the first sentence... This is the second, much longer sentence, with some additional puntuations?! Third sentence with a different length! Just a sentence ending with a number 980. Last but not least, the fourth sentence."; const arr = input.replace(/([.?!])\s*(?=[a-zA-Z0-9])/g, "$1|").split("|"); const maxLength = 105; // 期望输出数组 [ "This is the first sentence... This is the second, much longer sentence, with some additional puntuations?!", "Third sentence with a different length! Just a sentence ending with a number 980.", "Last but not least, the fourth sentence." ]
一、使用Array.reduce()迭代实现
这是最直观的实现方式,通过遍历句子数组逐步构建符合要求的块:
function mergeSentences(sentences, maxLength) { return sentences.reduce((chunks, sentence) => { // 初始化第一个块 if (chunks.length === 0) { return [sentence]; } const lastChunk = chunks[chunks.length - 1]; // 计算合并后的总长度(含空格) const combinedLength = lastChunk.length + 1 + sentence.length; if (combinedLength <= maxLength) { // 符合长度限制则合并到最后一个块 chunks[chunks.length - 1] = `${lastChunk} ${sentence}`; } else { // 超出限制则新增一个块 chunks.push(sentence); } return chunks; }, []); } // 调用示例 const result = mergeSentences(arr, maxLength); console.log(result);
逻辑说明:
- 以空数组作为初始结果容器
- 遍历每个句子时,检查与最后一个块合并后的长度是否合规
- 合规则合并,不合规则新增块,全程保持块内都是完整句子
二、使用递归实现
递归通过分治思想处理,每次处理当前句子与剩余句子的组合:
function mergeSentencesRecursive(sentences, maxLength, chunks = []) { // 终止条件:无剩余句子时返回结果 if (sentences.length === 0) { return chunks; } const [current, ...rest] = sentences; const lastChunk = chunks[chunks.length - 1]; if (!lastChunk) { // 无已存在块时,添加当前句子后递归处理剩余 return mergeSentencesRecursive(rest, maxLength, [...chunks, current]); } const combinedLength = lastChunk.length + 1 + current.length; if (combinedLength <= maxLength) { // 合并到最后一个块后递归 const updatedChunks = [...chunks.slice(0, -1), `${lastChunk} ${current}`]; return mergeSentencesRecursive(rest, maxLength, updatedChunks); } else { // 新增块后递归 return mergeSentencesRecursive(rest, maxLength, [...chunks, current]); } } // 调用示例 const resultRecursive = mergeSentencesRecursive(arr, maxLength); console.log(resultRecursive);
逻辑说明:
- 每次取出数组首个句子,判断能否与最后一个块合并
- 根据判断结果更新块数组,递归处理剩余句子
- 句子数组为空时返回最终块数组
三、哪种方式更优雅?
reduce迭代方案:代码简洁直观,符合常规阅读习惯,无递归栈溢出风险(适配超长数组),性能稳定,是日常开发的首选。- 递归方案:逻辑上符合分治思维,但对超长数组可能触发栈溢出,可读性不如迭代方案,仅在特定递归场景下有使用价值。
综上,递归并非最优雅的实现方式,Array.reduce()的迭代方案在可读性、性能和安全性上更优。
内容的提问来源于stack exchange,提问作者Sander Schnydrig
相关产品推荐
相关产品推荐

