0

I have an array of objects like below. Each object has permanent key 'type' and depending on the 'type', new keys are added.

So if type: 'text', we have a new key 'text'.

If type: 'notText', we have a new key 'attrs'.

arrayOfObj = [
    {
        "type": "text",
        "text": "="
    },
    {
        "type": "text",
        "text": " "
    },
    {
        "type": "text",
        "text": "S"
    },
    {
        "type": "text",
        "text": "O"
    },
    {
        "type": "notText",
        "attrs": {
            "id": 20,
            "data": "Something",
        }
    },
    {
        "type": "text",
        "text": "H"
    },
    {
        "type": "text",
        "text": "E"
    },
    {
        "type": "text",
        "text": "Y"
    },
    {
        "type": "notText",
        "attrs": {
            "id": 20,
            "data": "Other",
        }
    },
    {
        "type": "text",
        "text": "="
    },
    {
        "type": "text",
        "text": "T"
    },
    {
        "type": "text",
        "text": "O"
    },
]

The objects are in order, so depending on the 'type' of each item AND the order, then I need to combine them like so:

arrayOfObj = [
    {
        "type": "text",
        "text": "= SO"
    },
    {
        "type": "notText",
        "attrs": {
            "id": 20,
            "data": "Something",
        }
    }
    {
        "type": "text",
        "text": "HEY"
    },
    {
        "type": "notText",
        "attrs": {
            "id": 20,
            "data": "Other",
        }
    },
    {
        "type": "text",
        "text": "=TO"
    },
]

In summary, whenever 'type' = 'text' then combine every single object with type 'text' that are together. If the next object has type 'notText', then leave it alone until the next item with 'type' = 'text'. Then combine those.

I've asked a previous question that was similar to this with the working answer

let arrayOfObj = [{
    "type": "text",
    "text": "="
  },
  {
    "type": "text",
    "text": " "
  },
  {
    "type": "text",
    "text": "S"
  },
  {
    "type": "text",
    "text": "O"
  },
  {
    "type": "notText",
    "attrs": {
      "id": 20,
      "data": "Something",
    }
  },
  {
    "type": "text",
    "text": "H"
  },
  {
    "type": "text",
    "text": "E"
  },
  {
    "type": "text",
    "text": "Y"
  },
  {
    "type": "notText",
    "attrs": {
      "id": 20,
      "data": "Other",
    }
  },
  {
    "type": "text",
    "text": "="
  },
  {
    "type": "text",
    "text": "T"
  },
  {
    "type": "text",
    "text": "O"
  },
];
let newThing = arrayOfObj.reduce(
  (textKey, typeKey) => {
    if (typeKey.type === "text") {
      textKey[0].text += typeKey.text;
    } else {
      textKey.push({
        type: typeKey.type,
        attrs: typeKey.attrs
      });
    }
    return textKey;
  }, [{
    type: "text",
    text: ""
  }]
);
console.log(newThing);

However it combines all instances where 'type' = 'text' regardless or order or other objects with 'type' = 'notText'.

Would anyone have any idea of how to accomplish this?

4
  • what if there are 2 objects i.e notText comes together then what should happen? Commented Jul 15, 2021 at 12:42
  • Is the array always start by type: "text,? Commented Jul 15, 2021 at 12:43
  • Do you mean what if there are two objects in order with type 'notText'? In that case they would be left alone with their order maintained, only those with 'type' = 'text' need to be changed. Commented Jul 15, 2021 at 12:44
  • @ikhvjs Each object in the array will always have a 'type' key and if 'type': 'text' then it would always be in this format Commented Jul 15, 2021 at 12:46

3 Answers 3

2

I'd suggest using Array.reduce again, starting with an empty array.

If the last item in the array we build up is of type 'text', append the current item, otherwise just add it to the array:

const arrayOfObj = [ { "type": "text", "text": "=" }, { "type": "text", "text": " " }, { "type": "text", "text": "S" }, { "type": "text", "text": "O" }, { "type": "notText", "attrs": { "id": 20, "data": "Something", } }, { "type": "text", "text": "H" }, { "type": "text", "text": "E" }, { "type": "text", "text": "Y" }, { "type": "notText", "attrs": { "id": 20, "data": "Other", } }, { "type": "text", "text": "=" }, { "type": "text", "text": "T" }, { "type": "text", "text": "O" }, ]
    
const result = arrayOfObj.reduce((acc, curr) => {
    // If the last item was of type 'text' _and_ the current item is too.. append the text
    if (acc[acc.length-1]?.type === 'text' && curr.type === 'text') { 
        acc[acc.length-1].text += curr.text;
    } else {
        // Either current or last item in array was not type 'text' 
        acc.push(curr)
    }
    return acc;
}, []);

console.log('Result:', result);

Sign up to request clarification or add additional context in comments.

Comments

0

This is how you can do that:

arrayOfObj = [
    {
        "type": "text",
        "text": "="
    },
    {
        "type": "text",
        "text": " "
    },
    {
        "type": "text",
        "text": "S"
    },
    {
        "type": "text",
        "text": "O"
    },
    {
        "type": "notText",
        "attrs": {
            "id": 20,
            "data": "Something",
        }
    },
    {
        "type": "text",
        "text": "H"
    },
    {
        "type": "text",
        "text": "E"
    },
    {
        "type": "text",
        "text": "Y"
    },
    {
        "type": "notText",
        "attrs": {
            "id": 20,
            "data": "Other",
        }
    },
    {
        "type": "text",
        "text": "="
    },
    {
        "type": "text",
        "text": "T"
    },
    {
        "type": "text",
        "text": "O"
    },
]

let output = [];

arrayOfObj.forEach(x => {
  if (
    x.type == 'notText' ||
    output.length == 0 ||
    output[output.length - 1].type == 'notText'
  ) {
    output.push(x)
  } else {
    output[output.length - 1].text += x.text
  }
})

console.log(output);

Comments

0

You can use reduce here

const arrayOfObj = [
  { type: "text", text: "=" },
  { type: "text", text: " " },
  { type: "text", text: "S" },
  { type: "text", text: "O" },
  {
    type: "notText",
    attrs: { id: 20, data: "Something" },
  },
  { type: "text", text: "H" },
  { type: "text", text: "E" },
  { type: "text", text: "Y" },
  {
    type: "notText",
    attrs: { id: 20, data: "Other" },
  },
  { type: "text", text: "=" },
  { type: "text", text: "T" },
  { type: "text", text: "O" },
];

const result = arrayOfObj.reduce((acc, curr) => {
  const { type, ...props } = curr;
  const last = acc[acc.length - 1];
  if (!last || last.type !== "text" || last.type !== type) acc.push(curr);
  else last.text = last.text + props.text;
  return acc;
}, []);

console.log(result);

1 Comment

upvote for reusing last but downvote for not using curlys (if you want to be terse use ternary).

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.