[SOLVED] how to transform strin array in to array of objects with multiple elements

Issue

I have this array:

data: [
  ‘big text 1 here.’,
  ‘big text 2 here followed by list:’,
  '-this is list item;',
  '-this is another list item;',
  ‘big text 3 here followed by list:’,
  '-this is list item;',
  '-this is another list item;',
  '-this is another list item;',
  ‘big text 4 here.’
],

I want to turn it to something like:

data: [
  { 
   text: ‘big text 1 here.’
   list: []
  },
  { 
   text: ‘big text 2 here followed by list:’
   list: [
     '-this is list item;',
     '-this is another list item;'
   ]
  },
  { 
   text: ‘big text 3 here followed by list:’
   list: [
     '-this is list item;',
     '-this is another list item;',
     '-this is another list item;',
   ]
  },
  { 
   text: ‘big text 4 here.’
   list: []
  },
],

I am trying to achieve this this way

interface item {
  text: string;
  list: string[];
};

const newArr: item[] = [];

this.item.content.forEach((x, i) => {
  if(x.startsWith('-') && x.endsWith(';')) {
    //this is bullet list, need to add that to the previous item...
  } else {
    newArr.push({ text: x, list: []});
  }
});

I am not sure if I am doing it in a right way, because there is no way I can think of how to access previous element in newArr; Any ideas how to do it proper way?

Solution

I’d use Array.reduce for this

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]
}, [])

Playground link

Answered By – BorisTB

Answer Checked By – David Goodson (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *