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

优化带装饰文本节点合并算法求助:现有低效实现需改进

优化带装饰文本节点数组的合并算法

问题描述

需要合并两个带装饰的文本节点数组,每个节点包含文本、装饰(颜色、字体样式等)以及from/to索引,要求保持文本内容不变,同时合并装饰效果。当前算法遍历每个字符并为单个字符创建节点,效率极低,需优化。

当前低效算法代码

const getDecorationsByIndex = (nodes, index) => {
  const foundNodes: any[] = [];

  nodes.forEach(node => {
    if (index >= node.from && index < node.to) {
      foundNodes.push(node);
    }
  });

  return foundNodes.flatMap(node => node.textData?.decorations || []);
};

const mergeNodes = (nodes1, nodes2, content) => {
  const mergedNodes = [...content].map((s, index) => {
    const decorations1 = getDecorationsByIndex(nodes1, index);
    const decorations2 = getDecorationsByIndex(nodes2, index);

    return {
      id: '',
      nodes: [],
      type: Node_Type.TEXT,
      textData: {
        decorations: [...decorations1, ...decorations2],
        text: s,
      },
    };
  });

  return mergedNodes;
};

示例场景

文本内容为def:

  • 第一组节点(加粗效果):
[
  {
      "type": "TEXT",
      "id": "",
      "nodes": [],
      "textData": {
          "text": "de",
          "decorations": [
              {
                  "type": "BOLD",
                  "fontWeightValue": 700
              }
          ]
      },
      "from": 0,
      "to": 2
  },
  {
      "type": "TEXT",
      "id": "",
      "nodes": [],
      "textData": {
          "text": "f",
          "decorations": []
      },
      "from": 2,
      "to": 3
  }
]
  • 第二组节点(颜色效果):
[
  {
      "id": "",
      "nodes": [],
      "type": "TEXT",
      "textData": {
          "decorations": [
              {
                  "type": "COLOR",
                  "colorData": {
                      "foreground": "#d73a49"
                  }
              }
          ],
          "text": "def"
      },
      "from": 0,
      "to": 3
  }
]
  • 期望合并结果:
[
  {
      "type": "TEXT",
      "id": "",
      "nodes": [],
      "textData": {
          "text": "de",
          "decorations": [
              {
                  "type": "BOLD",
                  "fontWeightValue": 700
              },{
                  "type": "COLOR",
                  "colorData": {
                      "foreground": "#d73a49"
                  }
              }
          ]
      },
      "from": 0,
      "to": 2
  },
  {
      "type": "TEXT",
      "id": "",
      "nodes": [],
      "textData": {
          "text": "f",
          "decorations": [{
                  "type": "COLOR",
                  "colorData": {
                      "foreground": "#d73a49"
                  }
              }]
      },
      "from": 2,
      "to": 3
  }
]

优化思路与方案

1. 提取关键分割点

收集两组节点所有的from和to值,去重排序后得到文本区间的所有分割边界。比如示例中的分割点为0、2、3,这样只需处理分割后的连续区间,而非逐个字符。

2. 批量计算区间装饰

对每个分割出的区间[start, end),一次性筛选覆盖该区间的节点,合并其装饰集合,避免逐个字符查询的冗余操作。

3. 生成合并节点

根据区间的起止位置、合并后的装饰集合、对应文本内容,生成最终的合并节点。

优化后代码示例

const mergeNodesOptimized = (nodes1, nodes2, content) => {
  // 收集所有分割点
  const splitPoints = new Set<number>();
  [...nodes1, ...nodes2].forEach(node => {
    splitPoints.add(node.from);
    splitPoints.add(node.to);
  });
  // 排序分割点
  const sortedPoints = Array.from(splitPoints).sort((a, b) => a - b);
  
  const mergedNodes = [];
  
  for (let i = 0; i < sortedPoints.length - 1; i++) {
    const start = sortedPoints[i];
    const end = sortedPoints[i + 1];
    if (start >= end) continue; // 跳过无效区间
    
    // 获取当前区间在两组节点中的所有装饰
    const decorations1 = nodes1
      .filter(node => node.from <= start && node.to >= end)
      .flatMap(node => node.textData?.decorations || []);
    
    const decorations2 = nodes2
      .filter(node => node.from <= start && node.to >= end)
      .flatMap(node => node.textData?.decorations || []);
    
    // 合并装饰(可按需添加同类型装饰去重逻辑)
    const mergedDecorations = [...decorations1, ...decorations2];
    
    // 提取区间文本
    const text = content.slice(start, end);
    
    mergedNodes.push({
      id: '',
      nodes: [],
      type: Node_Type.TEXT,
      textData: {
        decorations: mergedDecorations,
        text: text,
      },
      from: start,
      to: end,
    });
  }
  
  return mergedNodes;
};

额外优化点

  • 装饰去重逻辑:如果存在同类型装饰(如两个COLOR),可按业务规则保留优先级高的(比如nodes2覆盖nodes1),用Map实现:
    const decorationMap = new Map();
    decorations1.forEach(deco => decorationMap.set(deco.type, deco));
    decorations2.forEach(deco => decorationMap.set(deco.type, deco));
    const mergedDecorations = Array.from(decorationMap.values());
    
  • 双指针筛选节点:若输入节点数组已按from排序,可使用双指针法快速定位覆盖当前区间的节点,进一步减少遍历次数。

内容的提问来源于stack exchange,提问作者developer1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 02:33:16