如何更改 reduce 函数以产生不同的结果

how to alter reduce function so it produce different result

我有这个数组:

data: [
  '+section1+',
  'big text 1 here.',
  'big text 2 here followed by list:',
  '-this is list item;',
  '-this is another list item;',
  '+section2+',
  'big text 3 here followed by list:',
  '-this is list item;',
  '-this is another list item;',
  '-this is another list item;',
  '+section3+', 
  'big text 4 here.'
],

我想将该数组转换为

"data": [
   {
    section: "section1",
    content: [
    {
      "text": "big text 1 here.",
      "list": []
    },
    }
    {
      "text": "big text 2 here followed by list:",
      "list": [
        "-this is list item;",
        "-this is another list item;"
      ]
    },
    ]
   }
   {
    section: "section2"
    content:[
    {
      "text": "big text 3 here followed by list:",
      "list": [
        "-this is list item;",
        "-this is another list item;",
        "-this is another list item;"
      ]
    },
    ]
   }
   {
   section: "section3",
   content: [
    {
      "text": "big text 4 here.",
      "list": []
    }
    ]
   }
  ]

我有关于 that:

的代码
interface DataItem {
    text: string
    list: string[]
}

function isListItem(item: string): boolean {
    return item.startsWith('-') && item.endsWith(';')
}

const transformedData = data.reduce<DataItem[]>((acc, item) => {
    // if item is list item
    if (isListItem(item)) {
        // get last DataItem from acc
        const lastDataItem = acc[acc.length - 1]

        // and use it as list item's parent
        if (lastDataItem) {
            lastDataItem.list.push(item)
        } else {
            console.error(`Parent text not found for list item ${item}`)
        }

        return acc
    }

    // if item is not list item, use it as new parent/DataItem
    const dataItem: DataItem = {
        text: item,
        list: []
    }

    return [...acc, dataItem]
}, [])

它缺少的是忽略部分。有什么想法可以修改该 reduce 函数以产生预期结果吗?

为了确定一个部分,我想出了这个函数:

function isSection(item: string): boolean {
    return item.startsWith('+') && item.endsWith('+')
}

应该这样做

const data= [
  '+section1+',
  'big text 1 here.',
  'big text 2 here followed by list:',
  '-this is list item;',
  '-this is another list item;',
  '+section2+',
  'big text 3 here followed by list:',
  '-this is list item;',
  '-this is another list item;',
  '-this is another list item;',
  '+section3+', 
  'big text 4 here.'
]



const result = data.reduce((res, item) =>{
  if(item.startsWith('+')){
    const section = item.substring(1, item.length -1)
    return[
        ...res,
       {
         section,
         content: []
       } 
      ]
  }
   const lastSectionIndex = res.length - 1
  if(item.startsWith('-')){
    const lastSection = res[lastSectionIndex]
    const lastContent = lastSection.content[lastSection.content.length -1]
    res[res.length - 1].content[lastSection.content.length -1].list.push(item.substring(1, item.length -1))
    return res
  }
  res[lastSectionIndex].content.push({text: item, list:[]})
 return res;

},[])

console.log(result)

我将使用我对 OP 的另一个(以前问过的)问题的回答中的相同方法... ... 并根据 OP 的新要求进行调整。

因此人们会留在reduce based approach which does not depend on outer scope references for keeping track of the currently to be built/aggregated property but instead makes this information part of the reducer function's first parameter, the previousValue which serves as an accumulator/collector object

至于 OP 的任务,此收集器将具有 2 个属性,sectionKeyresult,其中前者保存当前处理的 属性 名称的状态,以及后者是以编程方式构建的 result-array of section-items.

function aggregateStructuredTextItem(
  { sectionKey = '', result = [] },
  item
) {
  // try to retrieve the section specific text.
  let text = (item.match(/^\+\s*(.*?)\s*\+$/) || [])[1] ?? null;
  if (
    (text !== null) &&
    (text !== sectionKey)
  ) {
    // keep track of the currently processed section.    
    sectionKey = text;

    // create and collect new section entry.
    result.push({ section: text, content: [] });
  } else {
    // access the currently processed section.
    const section = result.at(-1);

    // try to retrieve the list specific text.
    text = (item.startsWith('-') && item.slice(1));
    if (text !== false) {

      // push list specific text into
      // the most recent content list.
      section.content.at(-1).list.push(text);
    } else {
      // create a content item and push it
      // into the most recent section content.
      section.content.push({ text: item, list: [] });
    }
  }
  return { sectionKey, result };
}

const textData = [
  '+section1+',
  'big text 1 here.',
  'big text 2 here followed by list:',
  '-this is list item;',
  '-this is another list item;',
  '+section2+',
  'big text 3 here followed by list:',
  '-this is list item;',
  '-this is another list item;',
  '-this is another list item;',
  '+section3+', 
  'big text 4 here.'
];
const structuredTextData = textData
  .reduce(aggregateStructuredTextItem, { result: [] })
  .result;

console.log({ textData, structuredTextData });
.as-console-wrapper { min-height: 100%!important; top: 0; }