提问人:developer1 提问时间:9/27/2023 最后编辑:developer1 更新时间:9/27/2023 访问量:49
优化算法,将文本节点与修饰合并
Optimize the algorithm to merge text nodes with decorations
问:
我需要帮助弄清楚如何合并两个带有装饰的节点数组。我有一个非常低效的算法,但我需要更好的东西或任何想法。
我有两个这样的文本节点数组。通常,每个节点都由文本和文本修饰(颜色、字体样式等)和索引组成。我想合并这两个数组,以便文本保持不变,但装饰将合并。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
}
]
结果应该是这些节点的一个数组,这些节点最终将具有相同的文本和所有装饰。帮助我优化我的算法或为我指明正确的方向,我应该如何合并这些节点。谢谢。
答:
0赞
trincot
9/27/2023
#1
您可以使用 from/to 信息按索引对节点进行排序(因此您需要复制节点,一次用于获取其属性,一次用于属性)。然后对其进行排序,并按该顺序迭代以跟踪哪些装饰处于活动状态或未处于活动状态。from
to
在开始之前,您还可以收集子字符串并从中重新生成字符串。然后可以在主算法中使用它来再次对其进行切片。
const Node_Type = { TEXT: 3 };
// Helper function to toggle a set member
const toggle = (set, member) => !set.delete(member) && set.add(member);
const extractText = (nodes) =>
// Reconstruct text from the nodes (there should be no inconsistency)
nodes.reduce((acc, node) => {
acc.length = Math.max(acc.length, node.from);
acc.splice(node.from, node.to - node.from, ...node.textData.text);
return acc;
}, []).map(ch => ch ?? " ").join("");
const mergeNodes = (nodes1, nodes2) => {
const nodes = nodes1.concat(nodes2);
const text = extractText(nodes);
const activeNodes = new Set;
return nodes.flatMap(node => [[node.from, node], [node.to, node]])
.sort(([a], [b]) => a - b)
.map(([from, node], i, toggles) => {
toggle(activeNodes, node); // Activate or deactivate a decoration
const to = toggles[i+1]?.[0] ?? text.length;
if (from === to || !activeNodes.size) return; // Nothing to generate here
return {
id: '',
nodes: [],
type: Node_Type.TEXT,
textData: {
decorations: Array.from(activeNodes, ({textData: {decorations}}) => decorations).flat(),
text: text.slice(from, to),
},
from,
to
};
}).filter(Boolean); // Exclude the undefined entries
}
// Sample input
const a = [{
"type": "TEXT", "id": "", "nodes": [],
"textData": { "text": "de", "decorations": [{"type": "BOLD","fontWeightValue": 700}] },
"from": 0, "to": 2
}, {
"type": "TEXT", "id": "", "nodes": [],
"textData": { "text": "f someFoo", "decorations": []},
"from": 2, "to": 11
}];
const b = [{
"id": "", "nodes": [], "type": "TEXT",
"textData": {
"decorations": [{"type": "COLOR","colorData": {"foreground": "#d73a49"}}],
"text": "def"
},
"from": 0, "to": 3
}, {
"id": "", "nodes": [], "type": "TEXT",
"textData": { "decorations": [], "text": " "},
"from": 3, "to": 4
}, {
"id": "", "nodes": [], "type": "TEXT",
"textData": {
"decorations": [{"type": "COLOR", "colorData": {"foreground": "#6f42c1"}}],
"text": "someFoo"
},
"from": 4, "to": 11
}];
console.log(mergeNodes(a, b));
请注意,共享装饰不会被克隆,因此某些节点的数组中将具有相同的对象引用。这意味着,如果您要改变装饰,它将应用于共享它的所有节点。如果你希望它以不同的方式工作,你应该在这个过程中克隆装饰。decorations
评论
text
text
contents
textData
content
contents