简体   繁体   中英

javascript - merge, combine, transform 2 different arrays of Objects

I can't figure it out how to transform and combine 2 arrays of object.

I have this 2 arrays of objects:

const selectedCourse = [
    {
      "courseType": [5],
      "id": 26,
      "title": "Apple Tart with Apricot Glaze",
  },
  {
    "courseType": [3],
    "id": 16,
    "title": "Classic Caesar Salad",
},
{
  "courseType": [1,2],
  "id": 10,
  "title": "Lobster Bisque",
},
{
  "courseType": [3],
  "id": 16,
  "title": "Classic Caesar Salad",
},
]

const courseTypes = [
{name: "Hors d'oeuvres", id: 0},
 {name: "Soup", id: 1},
 {name: "Fish", id: 2},
 {name: "Salad", id: 3},
 {name: "Main course", id: 4},
 {name: "Dessert", id: 5}
]

The courseType property inside the first JSON is an array of numbers that corresponds to courseTypes index and property id in the second JSON.

The result for this case should be this:

const result = [
  {
    courseType: 1,
    courseName: "Soup",
    courses: [
      {
        "courseType": [1,2],
        "id": 10,
        "title": "Lobster Bisque",
      }      
    ]
  },
  {
    courseType: 3,
    courseName: "Salad",
    courses: [
      {
        "courseType": [1,2],
        "id": 10,
        "title": "Lobster Bisque",
      }      
    ]
  },
  {
    courseType: 3,
    courseName: "Fish",
    courses: [
      {
        "courseType": [3],
        "id": 16,
        "title": "Classic Caesar Salad",
      },
      {
        "courseType": [3],
        "id": 16,
      },      
    ]
  },
  {
    courseType: 5,
    courseName: "Main course",
    courses: [
      {
        "courseType": [5],
        "id": 26,
        "title": "Apple Tart with Apricot Glaze",
      }
    ]
  }
]

The expected result have to combine the 2 arrays by filtering by courseType property.

Assuming, you want all items with selectedCourse , you could take a Map and collect all courses and later greate a new array out of the found values.

This solution includes Fish as well.

 const selectedCourse = [{ courseType: [5], id: 26, title: "Apple Tart with Apricot Glaze" }, { courseType: [3], id: 16, title: "Classic Caesar Salad" }, { courseType: [1, 2], id: 10, title: "Lobster Bisque" }, { courseType: [3], id: 16, title: "Classic Caesar Salad" }], courseTypes = [{ name: "Hors d'oeuvres", id: 0 }, { name: "Soup", id: 1 }, { name: "Fish", id: 2 }, { name: "Salad", id: 3 }, { name: "Main course", id: 4 }, { name: "Dessert", id: 5 }], map = selectedCourse.reduce((m, o) => o.courseType.reduce((n, id) => n.set(id, [...(n.get(id) || []), o]), m), new Map), result = courseTypes.reduce( (r, { name: courseName, id: courseType }) => (map.get(courseType) || []).reduce((s, courses) => s.concat({ courseType, courseName, courses }), r), [] ); console.log(result); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

You could use map and filter like this:

 const selectedCourse = [ { "courseType": [5], "id": 26, "title": "Apple Tart with Apricot Glaze", }, { "courseType": [3], "id": 16, "title": "Classic Caesar Salad", }, { "courseType": [1,2], "id": 10, "title": "Lobster Bisque", }, { "courseType": [3], "id": 16, "title": "Classic Caesar Salad", }, ] const courseTypes = [ {name: "Hors d'oeuvres", id: 0}, {name: "Soup", id: 1}, {name: "Fish", id: 2}, {name: "Salad", id: 3}, {name: "Main course", id: 4}, {name: "Dessert", id: 5} ]; const result = courseTypes.map(courseType => ({ courseType: courseType.id, courseName: courseType.name, courses: selectedCourse.filter(course => course.courseType.includes(courseType.id)) })).filter(extended => extended.courses.length); console.log(JSON.stringify(result, null, 2)); 

Explanation:

courseTypes.map iterates over your second input array and for each type it finds in selectedCourse which courses match with that particular type.

It uses .filter to collect those matches. The filter callback uses includes to determine if there is a match -- it returns a boolean, exactly what the filter callback expects as return value.

This filtered array is then added to an object literal that also defines the other two properties courseType and courseName . That new object is what the course type is mapped to. courseTypes.map returns an array of those objects.

Finally that result may have entries that have an empty courses array. Those are filtered out with another call to .filter . If the length of that courses array is non zero, the object is kept, otherwise it is kicked out of the result.

For older browsers

Here is the same code made compatible with older browsers (no arrow functions, no includes , which were introduced in ES2015):

 const selectedCourse = [ { "courseType": [5], "id": 26, "title": "Apple Tart with Apricot Glaze", }, { "courseType": [3], "id": 16, "title": "Classic Caesar Salad", }, { "courseType": [1,2], "id": 10, "title": "Lobster Bisque", }, { "courseType": [3], "id": 16, "title": "Classic Caesar Salad", }, ] const courseTypes = [ {name: "Hors d'oeuvres", id: 0}, {name: "Soup", id: 1}, {name: "Fish", id: 2}, {name: "Salad", id: 3}, {name: "Main course", id: 4}, {name: "Dessert", id: 5} ]; const result = courseTypes.map(function (courseType) { return { courseType: courseType.id, courseName: courseType.name, courses: selectedCourse.filter(function (course) { return course.courseType.indexOf(courseType.id) > -1; }) }; }).filter(function (extended) { return extended.courses.length; }); console.log(JSON.stringify(result, null, 2)); 

while "trincot" code is work fine for chrome and Mozila but it will not work in IE edge and IE 10 and below you need to convert it in pure javascript. below is code which will work in all browser.

if (!Array.prototype.includes) {
   Object.defineProperty(Array.prototype, 'includes', {
   value: function(searchElement, fromIndex) {

  if (this == null) {
    throw new TypeError('"this" is null or not defined');
  }

  // 1. Let O be ? ToObject(this value).
  var o = Object(this);

  // 2. Let len be ? ToLength(? Get(O, "length")).
  var len = o.length >>> 0;

  // 3. If len is 0, return false.
  if (len === 0) {
    return false;
  }

  // 4. Let n be ? ToInteger(fromIndex).
  //    (If fromIndex is undefined, this step produces the value 0.)
  var n = fromIndex | 0;

  // 5. If n ≥ 0, then
  //  a. Let k be n.
  // 6. Else n < 0,
  //  a. Let k be len + n.
  //  b. If k < 0, let k be 0.
  var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

  function sameValueZero(x, y) {
    return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
  }

  // 7. Repeat, while k < len
  while (k < len) {
    // a. Let elementK be the result of ? Get(O, ! ToString(k)).
    // b. If SameValueZero(searchElement, elementK) is true, return true.
    if (sameValueZero(o[k], searchElement)) {
      return true;
    }
    // c. Increase k by 1. 
    k++;
  }

  // 8. Return false
  return false;
    }
  });
}
var selectedCourse = [{ "courseType": [5], "id": 26, "title": "Apple Tart with Apricot Glaze" }, { "courseType": [3], "id": 16, "title": "Classic Caesar Salad" }, { "courseType": [1, 2], "id": 10, "title": "Lobster Bisque" }, { "courseType": [3], "id": 16, "title": "Classic Caesar Salad" }];
var courseTypes = [{ name: "Hors d'oeuvres", id: 0 }, { name: "Soup", id: 1 }, { name: "Fish", id: 2 }, { name: "Salad", id: 3 }, { name: "Main course", id: 4 }, { name: "Dessert", id: 5 }];
var result = courseTypes.map(function (courseType) {
return {
    courseType: courseType.id,
    courseName: courseType.name,
    courses: selectedCourse.filter(function (course) {
        return course.courseType.includes(courseType.id);
    })
  };
}).filter(function (extended) {
   return extended.courses.length;
});

 console.log(JSON.stringify(result, null, 2));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM