Phoenix
Phoenix

Reputation: 445

How can I merge an array of Objects with same keys in ES6 javascript?

How can I merge two arrays of Objects that have different keys pairs. I would be OK to use a library or ES6 features.

const listOfQuestions = [{
  question1: {
    important: true
  }
}, {
  question2: {
    important: false
  }
}]

const listOfAnswers = [{
  question1: {
    answer: false
  }
}, {
  question2: {
    answer: true
  }
}]

Expected result:

const result = [{
  "question1": {
    "important": true,
    "answer": false
  }
}, {
  "question2": {
    "important": false,
    "answer": true
  }
}]

I tried to use spread syntax:

const test = [...listOfQuestions, ...listOfAnswers]

But then I get something very out of what I needed:

[
  {
    "question1": {
      "important": true
    }
  }, {
    "question2": {
      "important": false
    }
  }, {
    "question1": {
      "answer": false
    }
  }, {
    "question2": {
      "answer": true
    }
  }
]

Upvotes: 0

Views: 12423

Answers (5)

charlietfl
charlietfl

Reputation: 171698

This structure is horrible to work with!!

That being said following uses a Map to store copies of question objects then loops through answers to extend objects in Map and finally converts Map values to array

const qMap = questions.reduce((m, q) => {
  const qKey = Object.keys(q)[0];
  return m.set(qKey, {[qKey]: Object.assign({}, q[qKey])});
}, new Map);

answers.forEach(a => {
  const qKey = Object.keys(a)[0];
  qMap.get(qKey) && Object.assign(qMap.get(qKey)[qKey], a[qKey]);
});

const res = [...qMap.values()];

console.log(res)
<script>
const questions = [{
  question1: {
    important: true
  }
}, {
  question2: {
    important: false
  }
}]

const answers = [{
  question1: {
    answer: false
  }
}, {
  question2: {
    answer: true
  }
}]
</script>

Upvotes: 0

Phoenix
Phoenix

Reputation: 445

Got very interesting code in the answers. I would like to mention that I also could achieve the result using the lodash method .merge().

const result = _.merge(listOfQuestions, listOfAnswers)

const listOfQuestions = [{question1:{important: true}}, {question2:{important: false}}]
const listOfAnswers = [{question1:{answer: false}}, {question2:{answer: true}}]

const result = _.merge(listOfQuestions, listOfAnswers)
console.log(result)
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

Upvotes: 2

Ivan
Ivan

Reputation: 40778

You can achieve this using the .map() function and returning a newly created array containing the bool important as well as the answer to each question.

const Q = [{question1:{important: true}}, {question2:{important: false}}]
const A = [{question1:{answer: false}}, {question2:{answer: true}}]

let testArr = Q.map(function(q, i) {
  return {
    ['question' + (i + 1)]: {
      important: q['question' + (i + 1)].important,
      answer: A[i]['question' + (i + 1)].answer
    }
  }
}, this);

console.log(testArr)

Upvotes: 1

Kevin Boucher
Kevin Boucher

Reputation: 16705

While I agree with Felix's comment in the OP that the data structure is not conducive to this operation, here is an example of merging these two arrays that assumes the object has only one key (that is the question identifier) and that the answers array always contains an item that corresponds to the questions array:

// jshint esnext: true

const listOfQuestions = [{question1:{important: true}}, {question2:{important: false}}];
const listOfAnswers = [{question1:{answer: false}}, {question2:{answer: true}}];

const merged = listOfQuestions.map((item) => {
  const obj = {};
  const key = Object.keys(item)[0];
  const question = item[key];
  const answer = listOfAnswers.find((answer) => {
    const answerKey = Object.keys(answer)[0];
    return key === answerKey;
  })[key];
  
  obj[key] = {...question, ...answer};
  
  return obj;
});

console.log(merged);

Uses the spread syntax, but overall this is probably not the best way to approach this problem.

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386881

You could collect the inner properties of every question in an object and render a new object with only one question in a new array.

const
    setHash = o => Object.entries(o).forEach(([k, v]) => Object.assign(hash[k] = hash[k] || {}, v));

var listOfQuestions = [{ question1: { important: true } }, { question2: { important: false } }],
    listOfAnswers = [{ question1: { answer: false } }, { question2: { answer: true } }],
    hash = Object.create(null),
    result;

listOfQuestions.forEach(setHash);
listOfAnswers.forEach(setHash);

result = Object.entries(hash).map(([k, v]) => ({ [k]: v }));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Related Questions