我可能需要使用其他数据结构,但我现在坚持使用这个解决方案。对此有任何建议将不胜感激。
现在我有这个数据结构:
const data = [
{
id: 'node-1',
type: 'text',
data: 'Hello,'
},
{
id: 'node-2',
type: 'text',
data: [
{
id: 'node-3',
type: 'text',
data: ' world.'
}
]
},
{
id: 'node-4',
type: 'text',
data: [
{
id: 'node-5',
type: 'text',
data: [
{
id: 'node-6',
type: 'text',
data: 'Foo bar'
}
]
}
]
}
]
我需要一个可以给出下一个结果的函数:
function split(arr, start_node, start_index, end_node, end_index) { ... }
const { before, range, after } = split(data, 'node-3', 3, 'node-6', 3)
// before
[
{
id: 'node-1',
type: 'text',
data: 'Hello,'
},
{
id: 'node-2',
type: 'text',
data: [
{
id: 'node-3',
type: 'text',
data: ' wo'
}
]
},
]
// range
[
{
id: 'node-2',
type: 'text',
data: [
{
id: 'node-3',
type: 'text',
data: 'rld.'
}
]
},
{
id: 'node-4',
type: 'text',
data: [
{
id: 'node-5',
type: 'text',
data: [
{
id: 'node-6',
type: 'text',
data: 'Foo'
}
]
}
]
}
]
// after
[
{
id: 'node-4',
type: 'text',
data: [
{
id: 'node-5',
type: 'text',
data: [
{
id: 'node-6',
type: 'text',
data: ' bar'
}
]
}
]
}
]
问题在于保持嵌套结构并有效地做到这一点。我想出的唯一解决方案是在三个不同的循环中进行此操作,但这显然无效
下面的代码将查找初始数据结构中的所有文本节点,并将每个节点转换为包含所有祖先的路径数组。
现在,您可以更轻松地将路径列表拆分为之前、之后和期间的路径列表。
最后,获取每个路径列表,并将它们转回常规对象。
const data = [{"id":"node-1","type":"text","data":"Hello,"},{"id":"node-2","type":"text","data":[{"id":"node-3","type":"text","data":" world."}]},{"id":"node-4","type":"text","data":[{"id":"node-5","type":"text","data":[{"id":"node-6","type":"text","data":"Foo bar"}]}]}]
function split(data, start_node, start_index, end_node, end_index) {
const paths = [];
const toPaths = (arr, path=[]) => arr.forEach(({id, type, data}) =>
Array.isArray(data) ? toPaths(data, [{id, type}, ...path]) : paths.push([{id, type, data}, ...path]))
toPaths(data)
const range = (paths, idMatch, index, type, state={inRegion: type==='before'}) =>
paths.flatMap(([a, ...b]) => {
if(a.id === idMatch ) {
state.inRegion = !state.inRegion;
return [[{
id: a.id,
type: a.type,
data: state.inRegion ? a.data.substring(index) : a.data.substring(0, index)}, ...b]];
}
else return state.inRegion ? [[a, ...b]] : [];
})
const pathsBefore = range(paths, start_node, start_index, 'before')
const pathsAfter = range(paths, end_node, end_index, 'after')
const pathsDuring = range(range(paths, start_node, start_index, 'after'), end_node, end_index, 'before')
const build = (paths, arr=[]) => {
paths.forEach(path => {
if(path.length) {
let last = structuredClone(path.pop());
last = arr.find(({id})=>id===last.id) ?? (arr.push(last), last);
if(path.length) {
last.data??=[];
build([path], last.data);
}
}
})
return arr
}
return {
before: build(pathsBefore),
range: build(pathsDuring),
after: build(pathsAfter),
}
}
const { before, range, after } = split(data, 'node-3', 3, 'node-6', 3);
console.log('------- before:');
console.log(JSON.stringify(before, null, 2))
console.log('------- range:');
console.log(JSON.stringify(range, null, 2))
console.log('------- after:');
console.log(JSON.stringify(after, null, 2))