如何用函数式方法将列表转为同值嵌套列表?求Ramda实现方案
嘿,这个连续相同元素分组的需求,用函数式方式实现完全没问题!你提到的Ramda mapAccum确实是个合适的工具,我来给你捋清楚思路,顺便再补个更简洁的reduce方案~
用Ramda mapAccum实现
mapAccum的核心是同时维护累加器和生成结果序列,刚好匹配我们需要跟踪“当前正在收集的分组”的场景。具体思路是:
- 用累加器保存当前分组的元素值和已收集的数组
- 遍历数组时,判断当前元素是否和累加器里的元素值一致:一致就追加到当前分组;不一致就把当前分组输出为结果项,然后启动新的分组
- 最后别忘了把最后一个未输出的分组补上
代码实现如下:
const { mapAccum, append, init, last } = require('ramda'); const groupConsecutive = (arr) => { if (arr.length === 0) return []; // 初始化累加器:[当前分组的元素值, 当前收集的数组] const initialAcc = [arr[0], [arr[0]]]; // 从第二个元素开始遍历处理 const [finalAcc, intermediateGroups] = mapAccum( ([currentVal, currentGroup], val) => { if (val === currentVal) { // 相同元素:更新当前分组,暂不输出结果 return [[currentVal, append(val, currentGroup)], null]; } else { // 不同元素:输出当前分组,启动新的分组 return [[val, [val]], currentGroup]; } }, initialAcc, arr.slice(1) ); // 过滤掉中间结果里的null,再加上最后一个分组 return [...intermediateGroups.filter(Boolean), finalAcc[1]]; }; // 测试验证 console.log(groupConsecutive([1,1,1,2,2,1,1])); // 输出 [[1,1,1], [2,2], [1,1]]
更简洁的Ramda reduce实现
如果觉得mapAccum的逻辑有点绕,用reduce也能写出非常清晰的函数式代码,思路更直接:
- 累加器就是已经完成分组的数组
- 每次迭代检查最后一个分组的最后一个元素是否和当前元素相同,相同就追加,不同就新增分组
代码如下:
const { reduce, append, last, init } = require('ramda'); const groupConsecutive = reduce((acc, val) => { if (acc.length === 0) { return [[val]]; } const lastGroup = last(acc); return lastGroup[lastGroup.length - 1] === val ? append(append(val, lastGroup), init(acc)) // 追加到最后一个分组 : append([val], acc); // 新增分组 }, []); // 测试验证 console.log(groupConsecutive([1,1,1,2,2,1,1])); // 输出 [[1,1,1], [2,2], [1,1]]
两种方案都是纯函数式的实现,没有副作用,完全符合你的需求~
内容的提问来源于stack exchange,提问作者donnut
相关产品推荐
相关产品推荐

