3
\$\begingroup\$

I'm trying to group all the types which have ordered-list-item & unordered-list-item into new object.

How can I simplify the function and reduce multiple return statements?

const data = {
  data: [{
    areas: [{
        sections: [{
          rjf: [{
              "type": "heading-1",
              "text": "A title",
            },
            {
              "type": "ordered-list-item",
              "text": "Ordered Item A",
            },
            {
              "type": "unordered-list-item",
              "text": "Ordered Item B",
            },
            {
              "type": "heading-1",
              "text": "A title",
            }
          ]
        }]
      },
      {
        sections: [{
          rjf: [{
              "type": "heading-1",
              "text": "Block 2 A title",
            },
            {
              "type": "ordered-list-item",
              "text": "Block 2 Ordered Item A",
            },
            {
              "type": "unordered-list-item",
              "text": "Block 2 Ordered Item B",
            },
            {
              "type": "heading-1",
              "text": "Block 2 A title",
            }
          ]
        }]
      }
    ]
  }]
};

function parseAreas() {
  data[0].areas.forEach(area => {
    this.moveToNewObject(area);
  })
}


function moveToNewObject(data) {
  const areas = data[0].areas;
  //console.log(data[0].areas)
  const listItemTypes = ['unordered-list-item', 'ordered-list-item'];
  return areas.map((area) => {
    var sec = area.sections;
    return sec.map((section) => {
      let lastHeadingIndex = -1;
      return section.rjf.reduce((acc, current, index) => {
        if (!current.type || !listItemTypes.includes(current.type)) {
          lastHeadingIndex = acc.length;
          return [...acc, current]
        } else {
          let listObject = acc.find((el, i) => i > lastHeadingIndex && i < index && el.type === 'list');
          if (!listObject) {
            listObject = {
              type: 'list',
              items: [current]
            }
            return [...acc, listObject];
          }
          listObject.items = [...listObject.items, current];
          return acc;
        }
      }, [])
    });
  });
}
console.log('sections', moveToNewObject(data.data));

\$\endgroup\$
1
  • 1
    \$\begingroup\$ an you give an example of what you expect the output to be? It's not clear from the description what the expected behavour is. \$\endgroup\$ Commented May 11, 2019 at 20:22

1 Answer 1

1
\$\begingroup\$

How can I simplify the function and reduce multiple return statements?

You could reduce the number of return statements by building up the new object in a more imperative way, without using the map and reduce functions, but I'm not sure that would be better. I think it's fine using functions as it is.

This part doesn't look great:

  let listObject = acc.find((el, i) => i > lastHeadingIndex && i < index && el.type === 'list');

The problem with it is that you are using lastHeadingIndex to find the last heading added in acc, but acc.find will search from the beginning. With a large data, that would be a waste, instead of searching from the end.

In fact, I'm wondering if lastHeadingIndex is important at all. Isn't your real intention more like "consecutive items of list type should be combined into a list object"? If that's the case, then you don't need to search from the end, it's enough to look at the last item of acc: if it's a list type, then append to it, if not, then create a new list type.

If this is indeed your real intention, then you could get rid of lastHeadingIndex, and write a bit simpler:

function moveToNewObject(data) {
  const listItemTypes = ['unordered-list-item', 'ordered-list-item'];
  return data[0].areas.map(area => {
    var sec = area.sections;
    return sec.map(section => {
      return section.rjf.reduce((acc, current, index) => {
        if (!listItemTypes.includes(current.type)) {
          acc.push(current);
          return acc;
        }

        if (!acc.length || acc[acc.length - 1].type !== 'list') {
          acc.push({type: 'list', items: [current]});
          return acc;
        }

        acc[acc.length - 1].items.push(current);
        return acc;
      }, [])
    });
  });
}

I would also change the name of the function, because moveToNewObject sounds overly generic, it doesn't seem to describe its real purpose. How about combineListItemTypes, or transformCombiningListItemTypes?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.