0

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
    }
  }
]
mplungjan
  • 169,008
  • 28
  • 173
  • 236
Phoenix
  • 437
  • 3
  • 6
  • 15
  • 2
    please add your try. btw, why different keys and an array. if different keys are wanted, why not use just a single object? – Nina Scholz May 29 '18 at 20:58
  • Agree. Or flatten the objects in array and add a common property like `'question: 1`. Please note it is expected you show what you have tried. Stackoverflow is not a free code writing service or *"how to"* tutorial service – charlietfl May 29 '18 at 21:00
  • [`...` is not an operator!](https://stackoverflow.com/questions/37151966/what-is-spreadelement-in-ecmascript-documentation-is-it-the-same-as-spread-oper/37152508#37152508) – Felix Kling May 29 '18 at 21:07
  • does the arrays have the same question at the same index? – Nina Scholz May 29 '18 at 21:07
  • 2
    The structure of your data is unfavorable . Why do you have an array of objects where each object has a different property name? Either have a single object with all questions or an array where each object has the same structure. – Felix Kling May 29 '18 at 21:08
  • 1
    I see your point, but imagine you have list of question from Source A and need to compare with the answers from Source B. And Source B only stores the answer. – Phoenix May 29 '18 at 21:45

5 Answers5

3

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/lodash@4.17.10/lodash.min.js"></script>
Ivan
  • 34,531
  • 8
  • 55
  • 100
Phoenix
  • 437
  • 3
  • 6
  • 15
1

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; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

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.

Kevin Boucher
  • 16,426
  • 3
  • 48
  • 55
1

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)
Ivan
  • 34,531
  • 8
  • 55
  • 100
  • 1
    This is nice. The downside is that it is not using the existing object key name. Imagine you need to keep the key name for further reference (instead of question1, it is "city-question", or "rent-question" etc. – Phoenix May 29 '18 at 21:43
0

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>
charlietfl
  • 170,828
  • 13
  • 121
  • 150