3

I have two large files containing object arrays, the first containing data like this:

[{
    "id": "001",
    "word": "abbess",
    "def": "(noun) The lady superior of a nunnery",
}, {
    "id": "002"
    "word": "abbey",
    "def": "(noun) The group of buildings which collectively form the dwelling-place of a society of monks or nuns.",
}, (etc...)

The second, data like this:

[{
    "meta": {
        "term": "abbess",
        "part_of_speech": "noun",
        "definition": "The lady superior of a nunnery"
    }
}, {
    "meta": {
        "term": "abbey",
        "part_of_speech": "noun",
        "definition": "The group of buildings which collectively form the dwelling-place of a society of monks or nuns"
    }
}, (etc...)

I want to combine these two files so the "meta" information from the second file is added to the corresponding information from the first file, so:

[{
    "id": "001",
    "word": "abbess",
    "def": "(noun) The lady superior of a nunnery",
    "meta": {
        "term": "abbess",
        "part_of_speech": "noun",
        "definition": "The lady superior of a nunnery"
    }
}, {
    "id": "002"
    "word": "abbey - (noun) The group of buildings which collectively form the dwelling-place of a society of monks or nuns.",
    "def": "(noun) The group of buildings which collectively form the dwelling-place of a society of monks or nuns.",
    "meta": {
        "term": "abbey",
        "part_of_speech": "noun",
        "definition": "The group of buildings which collectively form the dwelling-place of a society of monks or nuns"
    }
}, (etc...)

Right now, I'm have this code

 var newArr = [];
 for(var i = 0; i < meta.length; i++) {
    newArr.push(words[i]);
    newArr.push(meta[i]);
 }

that adds the meta objects after the words object, not within. Do I need to loop down another layer to add the meta objects within the words objects, or is there a different method that would work better here, like .concat()?

5 Answers5

2

If each element in each array corresponds to the other element with the same index in the other array, then it's a simple .map, which is more appropriate than a for loop:

const input1 = [{
    "id": "001",
    "word": "abbess",
    "def": "(noun) The lady superior of a nunnery",
}, {
    "id": "002",
    "word": "abbey",
    "def": "(noun) The group of buildings which collectively form the dwelling-place of a society of monks or nuns.",
}];
const input2 = [{
    "meta": {
        "term": "abbess",
        "part_of_speech": "noun",
        "definition": "The lady superior of a nunnery"
    }
}, {
    "meta": {
        "term": "abbey",
        "part_of_speech": "noun",
        "definition": "The group of buildings which collectively form the dwelling-place of a society of monks or nuns"
    }
}];
const combined = input1.map((item) => {
  const { word } = item ;
  const foundInput2 = input2.find(({ meta: { term }}) => term === word);
  const { meta } = foundInput2;
  return { ...item, meta };
});
console.log(combined);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • I like your answer, I am still getting used to using Map(), could you take your map functionality to compare the term to word properties and look for string equality so you don't have to depend on the indexes being the same? – Ryan Wilson Apr 23 '18 at 23:34
  • Easy to tweak, just use `.find` to find the other object instead – CertainPerformance Apr 23 '18 at 23:37
  • Thanks for that snippet. Still trying to get used to the llambda syntax in javascript, been using it in C# more so I'm starting to be able to read it pretty well. Didn't know you could do a return statement like that concatinating the objects together, +1 from me sir. – Ryan Wilson Apr 23 '18 at 23:40
2

loop through the array of metas and use Object.assign to add the meta to the corresponding object in the first array :

var arr = [{
  "id": "001",
  "word": "abbess",
  "def": "(noun) The lady superior of a nunnery",
}, {
  "id": "002",
  "word": "abbey",
  "def": "(noun) The group of buildings which collectively form the dwelling-place of a society of monks or nuns.",
}]

const arr2 = [{
  "meta": {
    "term": "abbess",
    "part_of_speech": "noun",
    "definition": "The lady superior of a nunnery"
  }
}, {
  "meta": {
    "term": "abbey",
    "part_of_speech": "noun",
    "definition": "The group of buildings which collectively form the dwelling-place of a society of monks or nuns"
  }
}]

arr2.forEach((e, i) => {
  Object.assign(arr[i], e);
});

console.log(arr)
Taki
  • 17,320
  • 4
  • 26
  • 47
1

In case the arrays doesn't line up, you can use .map and .find to achieve your goal.

const input1 = [{
    "id": "001",
    "word": "abbess",
    "def": "(noun) The lady superior of a nunnery",
}, {
    "id": "002",
    "word": "abbey",
    "def": "(noun) The group of buildings which collectively form the dwelling-place of a society of monks or nuns.",
}];
const input2 = [{
    "meta": {
        "term": "abbess",
        "part_of_speech": "noun",
        "definition": "The lady superior of a nunnery"
    }
}, {
    "meta": {
        "term": "abbey",
        "part_of_speech": "noun",
        "definition": "The group of buildings which collectively form the dwelling-place of a society of monks or nuns"
    }
}];

const output = input1.map(item => {
    return { 
      ...item, 
      ...input2.find(item2 => item2.meta.term === item.word)
    }
});

console.log(output);
Marcos Casagrande
  • 37,983
  • 8
  • 84
  • 98
0

Just set the new property of the object from the first array.

 var newArr = [];
 for(var i = 0; i < meta.length; i++) {
    var word = words[i];
    word.meta = meta[i].meta;
    newArr.push(word);
 }

This is assuming that both arrays will always have info of the same word in the same order.

Bonus tip - if you are using ECMAScript 6, you could concatenate the objects like this:

 const newArr = [];
 for(let i = 0; i < meta.length; i++) {
    newArr.push({ ...words[i], ...meta[i]} );
 }
Mark E
  • 3,403
  • 2
  • 22
  • 36
0

An alternative is using the function reduce + function map

The function reduce converts the second array input2 to an object where keys are coming from the attribute meta.term, this way the function map uses that object to find very fast the corresponding meta values by key rather than a repeated find execution.

This approach works independently of the order because will match the attributes word and attributes meta.term.

const input1 = [{    "id": "001",    "word": "abbess",    "def": "(noun) The lady superior of a nunnery",}, {    "id": "002",    "word": "abbey",    "def": "(noun) The group of buildings which collectively form the dwelling-place of a society of monks or nuns.",}],
      input2 = [{    "meta": {        "term": "abbess",        "part_of_speech": "noun",        "definition": "The lady superior of a nunnery"    }}, {    "meta": {        "term": "abbey",        "part_of_speech": "noun",        "definition": "The group of buildings which collectively form the dwelling-place of a society of monks or nuns"    }}],
      mapped = input2.reduce((a, o) => Object.assign(a, {[o.meta.term]: o.meta}), {}),
      result = input1.map((o) => Object.assign({}, o, {meta: mapped[o.word]}));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ele
  • 33,468
  • 7
  • 37
  • 75