Home > Software engineering >  Javascript Combine Array by Other Array Based on Multiple Values
Javascript Combine Array by Other Array Based on Multiple Values

Time:05-12

I have an array called p which looks like:

[
  {
    "Day": "Monday",
    "data": [
      "chest",
      "triceps",
      "shoulders"
    ]
  },
  {
    "Day": "Tuesday",
    "data": [
      "back",
      "biceps"
    ]
  },
  {
    "Day": "Thursday",
    "data": [
      "legs"
    ]
  }
]

and I have another array, program which looks like: (skimmed down)

[
  {
    "target": "biceps",
    "data": [
      {
        "name": "barbell alternate biceps curl",
        "target": "biceps"
      },
      {
        "name": "barbell lying preacher curl",
        "target": "biceps"
      }
    ]
  },
  {
    "target": "triceps",
    "data": [
      {
        "name": "barbell incline reverse-grip press",
        "target": "triceps"
      },
      {
        "name": "barbell lying extension",
        "target": "triceps"
      }
    ]
  }
]

I need program to group the muscle groups that p.data has. It should look like:

[
      {
        "target": "chest tricep shoulder",
        "data": [
          {
            "name": "chest exercise",
            "target": "chest"
          },

          {
            "name": "tricep exercise",
            "target": "tricep"
          },
          {
            "name": "shoulder exercise",
            "target": "shoulder"
          },
        ]
      },

      {
        "target": "back biceps",
        "data": [
          {
            "name": "back exercise",
            "target": "back"
          },

          {
            "name": "bicep exercise",
            "target": "bicep"
          },
        ]
      },
]

I have tried this (sort based off array), but not the right attempt:

function mapOrder(array, order, property) {
  let ordered = [], unordered = [];

  // Iterate over each item in the supplied array of objects, separating ordered and unordered objects into their own arrays.
  array.forEach((item) => {
  if (order.indexOf(item[property]) === -1) {
      unordered.push(item);
  } else {
      ordered.push(item);
  }
  });

  // Sort the ordered array.
  ordered.sort((a, b) => {
  a = a[property], b = b[property];

  if (order.indexOf(a) < order.indexOf(b)) {
      return -1;
  } else {
      return 1;
  }
  });

  // Sort the unordered array.
  unordered.sort((a, b) => {
  a = a[property], b = b[property];

  if (a < b) {
      return -1;
  } else if (a > b) {
      return 1;
  } else {
      return 0;
  }
  });

  // Append the sorted, non-ordered array to the sorted, ordered array.
  ordered.push(...unordered);

  return ordered;
}

CodePudding user response:

You can use the following implementation:

const programs = [
  {
    target: "biceps",
    data: [
      {
        name: "barbell alternate biceps curl",
        target: "biceps",
      },
      {
        name: "barbell lying preacher curl",
        target: "biceps",
      },
    ],
  },
  {
    target: "triceps",
    data: [
      {
        name: "barbell incline reverse-grip press",
        target: "triceps",
      },
      {
        name: "barbell lying extension",
        target: "triceps",
      },
    ],
  },
];

// creates a Map which maps
// muscle => Array of exercises
const lookupTable = programs.reduce(
  (map, { target, data }) => (map.set(target, data), map),
  new Map()
);

const p = [
  {
    Day: "Monday",
    data: ["chest", "triceps", "shoulders"],
  },
  {
    Day: "Tuesday",
    data: ["back", "biceps"],
  },
  {
    Day: "Thursday",
    data: ["legs"],
  },
];

// for each day map the respective exercises
const result = p.map((day) => ({
  // join together the muscles to a muscle group
  target: day.data.join(" "),
  // for each muscle get the respective exercises and put them in a list
  // if a muscle does not exist (as here in this limited example) set some default value (please adjust as you please)
  data: day.data.flatMap(
    (muscle) =>
      lookupTable.get(muscle) || {
        name: `Muscle ${muscle} does not exist`,
        target: muscle,
      }
  ),
}));
console.log(JSON.stringify(result, null, 4));
.as-console-wrapper { max-height: 100% !important; top: 0; }

First I create a lookup table using a Map which will allow for fast lookups in O(1) and maps a given muscle to an array of corresponding exercises as shown below.

I use reduce() for this but that's not required. You could just create the Map beforehand and manually add the arrays within a loop over the array.

Map(2) {
  'biceps' => [
    { name: 'barbell alternate biceps curl', target: 'biceps' },
    { name: 'barbell lying preacher curl', target: 'biceps' }
  ],
  'triceps' => [
    { name: 'barbell incline reverse-grip press', target: 'triceps' },
    { name: 'barbell lying extension', target: 'triceps' }
  ]
}

Then I use map() and flatMap() to create a training plan for each day containing all the exercises for all the named muscles that day. To create the string for the muscle group we can just join() the array of muscles.

  • Related