1

I have an array of json 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",
        }
    }
]

Depending on the 'type' of each item i.e. if type: 'text', then I need to combine each 'text' into 1 object like so:

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

I know that to start it I can use

if(this.arrayOfObj.map(ed=>ed.type) === 'text') {
      Object.assign({}, ...arrayOfObj);           
}

However it doesn't quite work and I'm unsure of how to go further.

Would anyone have any idea of how to accomplish this?

4
  • What happens if for a given type you have a mix of text and attr? What should we do then? Commented Jul 15, 2021 at 9:46
  • There's only two values that 'type' could be, which is either 'text' or 'notText'. If it's 'text' then automatically a 'text' key will be included and if it's 'notText' then an 'attr' will be included. There won't be a obj with both 'text' and 'attr'. The issue isn't quite creating the keys it's more assigning values to the keys. Commented Jul 15, 2021 at 9:49
  • How to combine "type": "notText" object into one? Commented Jul 15, 2021 at 9:50
  • No it's more if 'type' = 'text', then combine the 'text' of all objects with 'type' = 'text', there's an example above with arrayOfObj. So starting with the first arrayOfObj, how to get to the second. Commented Jul 15, 2021 at 9:52

5 Answers 5

2

Example below.

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

const output = arrayOfObj.reduce(
  (a, b) => {
    if (b.type === "text") {
      a[0].text += b.text;
    } else {
      a.push({
        type: b.type,
        attrs: b.attrs,
      });
    }
    return a;
  },
  [{ type: "text", text: "" }]
);

console.log(output);

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

Comments

1

You can use reduce method to do this.

arrayOfObj = [{
    "type": "text",
    "text": "="
  },
  {
    "type": "text",
    "text": " "
  },
  {
    "type": "text",
    "text": "S"
  },
  {
    "type": "text",
    "text": "O"
  },
  {
    "type": "notText",
    "attrs": {
      "id": 20,
      "data": "Something",
    }
  },
  {
    "type": "notText",
    "attrs": {
      "id": 22,
      "data": "Something",
    }
  }
]

const t = arrayOfObj.reduce((acc, curr) => {
  if (curr.type === "text") {
    const accTypeText = acc.find((v) => v.type === "text");
    if (accTypeText) {
      accTypeText.text += curr.text;
      return [...acc];
    }
  }
  return [...acc, curr];
}, [])

console.log(t);

Note: the map method return an array, so your if statement return always false

Comments

1

We can use Array.reduce to create the desired object from the arrayOfObj input, if it is of type 'text' concatenate, otherwise just set the attrs.

const arrayOfObj = [ { "type": "text", "text": "=" }, { "type": "text", "text": " " }, { "type": "text", "text": "S" }, { "type": "text", "text": "O" }, { "type": "notText", "attrs": { "id": 20, "data": "Something", } }, { "type": "someOtherType", "attrs": { "id": 35, "data": "Something else", } } ]
    
const result = Object.values(arrayOfObj.reduce((acc, { type, text, attrs }) => { 
    if (!acc[type]) acc[type] = { type };
    if (type === 'text') acc[type].text = (acc[type].text || '') + text;
    if (type !== 'text') acc[type].attrs = attrs;
    return acc;
}, {}));

console.log('Result:', result)

Comments

1

I am breaking the problem step by step, I would do this:

let arrayOfObj = [ { "type": "text", "text": "=" }, { "type": "text", "text": " " }, { "type": "text", "text": "S" }, { "type": "text", "text": "O" }, { "type": "notText", "attrs": { "id": 20, "data": "Something", } } ]
let completeString = "";

arrayOfObj.forEach(x => x.type == "text" ? completeString += x.text : "")
arrayOfObj = arrayOfObj.filter(x => x.type == "notText");
arrayOfObj.push({ "type": "text", "text": completeString })

console.log(arrayOfObj);

Comments

0

This is how I would do it. A similar idea to @R3tep &@ikhvjs's answers using reduce, only much less elegant.

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

function combineTexts(arrayOfObj) { 
    let noTextArray = arrayOfObj.filter(i => i.type !== 'text');
    let allTexts = arrayOfObj.filter(i => i.type === 'text')
                             .map(i => i.text)
                             .reduce((a, b) => a + b, '');
    noTextArray.unshift({ type: 'text', text: allTexts });
    return noTextArray;
}

console.log(combineTexts(arrayOfObj))

Comments

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.