You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用函数式方法将列表转为同值嵌套列表?求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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:39:31