如何在给定索引处拆分字符串节点数组?

问题描述 投票:0回答:1

我可能需要使用其他数据结构,但我现在坚持使用这个解决方案。对此有任何建议将不胜感激。

现在我有这个数据结构:

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'
                    }
                ]
            }
        ]
    }
]

问题在于保持嵌套结构并有效地做到这一点。我想出的唯一解决方案是在三个不同的循环中进行此操作,但这显然无效

javascript algorithm text text-processing
1个回答
0
投票

下面的代码将查找初始数据结构中的所有文本节点,并将每个节点转换为包含所有祖先的路径数组。

现在,您可以更轻松地将路径列表拆分为之前、之后和期间的路径列表。

最后,获取每个路径列表,并将它们转回常规对象。

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))

© www.soinside.com 2019 - 2024. All rights reserved.