Search code examples
javascriptarraysjavascript-objectsfrequency

JavaScript array frequency meaasure object properties


I'm dealing with some logic that I can't seem to find a solution to. I hope you can help me solve this problem. I have the following array:

const exampleDay = [
  exercise.prehab.jointRotations,
  exercise.prehab.upperbody,
  exercise.skillTechnique.planche,
  exercise.skillTechnique.HSPU,
  exercise.strengthPrimary.upperbody.horPress,
  exercise.strengthSecondary.upperbody.incPress,
  exercise.strengthPrimary.upperbody.verPress,
  exercise.strengthIsolation.upperbody.biceps,
  exercise.strengthIsolation.upperbody.sideDelts,
  exercise.strengthIsolation.upperbody.rearDelts,
  exercise.mobility.traction
];

The object I am referring to in this array can be found here:

const exercises = {
  prehab: {
    jointRotations: <p className="prehab">Joint Rotations</p>,
    upperbody: <p className="prehab">Upper Body Prehab</p>,
    lowerbody: <p className="prehab">Lower Body Prehab</p>,
    scaps: <p className="prehab">Scaps</p>
  },
  skillTechnique: {
    core: <p className="skill">Core</p>,
    frontLever: <p className="skill">Front Lever Technique</p>,
    planche: <p className="skill">Planche Technique</p>,
    HSPU: <p className="skill">HSPU Technique</p>
  },
  strengthPrimary: {
    upperbody: {
      horPress: <p className="strength">Horizontal Press</p>,
      incPress: <p className="strength">Incline Press</p>,
      verPress: <p className="strength">Vertical Press</p>,
      horPull: <p className="strength">Horizontal Pull</p>,
      verPull: <p className="strength">Vertical Pull</p>
    },
    lowerbody: {
      quad: <p className="strength">Quad</p>,
      hamGlute: <p className="strength">Ham/Glute</p>
    }
  },
  strengthSecondary: {
    upperbody: {
      horPress: <p className="strength">Horizontal Press Sec</p>,
      incPress: <p className="strength">Incline Press Sec</p>,
      verPress: <p className="strength">Vertical Press Sec</p>,
      horPull: <p className="strength">Horizontal Pull Sec</p>,
      verPull: <p className="strength">Vertical Pull Sec</p>
    },
    lowerbody: {
      quad: <p className="strength">Quad Sec</p>,
      hamGlute: <p className="strength">Ham/Glute Sec</p>
    }
  },
  strengthIsolation: {
    upperbody: {
      elbow: <p className="strength">Elbow Prep</p>,
      sideDelts: <p className="strength">Side Delts</p>,
      rearDelts: <p className="strength">Rear Delts</p>,
      biceps: <p className="strength">Biceps</p>
    },
    lowerbody: {
      quad: <p className="strength">Quads</p>,
      hamstrings: <p className="strength">Hamstrings</p>,
      calves: <p className="strength">Calves</p>
    }
  },
  mobility: {
    traction: <p className="mobility">Mobility 1 Traction</p>,
    tension: <p className="mobility">Mobility 2 Tension</p>
  }
};

I want to make a function that can measure the frequency of the amount of exercise.prehab, exercise.skillTechnique in my array. This function would for example return an array that looks like:

[{prehab: 2}, {skillTechnique: 2}, {strengthPrimary: 2}, {strengthSecondary: 1}, {strengthIsolation: 3},  {mobility: 1}]

I'm not sure how I can access a parent object property from the array that I made now. Any ideas? Thank you in advance!


Solution

  • I want to make a function that can measure the frequency of the amount of exercise.prehab, exercise.skillTechnique in my array.

    You can't, reliably in the general case.

    I'm not sure how I can access a parent object property from the array that I made now.

    You can't. What's in your array is just the value that exercise.prehab.jointRotations (for instance) had as of the moment you created the array. There is no ongoing link between the value in the array and the value in the exercise.prehab object.

    Now, if all of the values are unique (it looks like they probably are), you can go hunting for them using a function like this:

    function findParent(data, targetValue) {
        for (const value of Object.values(data)) {
            if (value === targetValue) {
                return data;
            }
            if (value && typeof value === "object") {
                const found = findParent(value, targetValue);
                if (found) {
                    return found;
                }
             }
        }
        return null; // Not found
    }
    

    That's a function that recursively searches the object you pass it for a target value. So you can found the parent object (if any) of exampleDay[0] by doing findParent(exercises, exampleDay[0]).

    But as soon as there's any duplication, that won't work. And in any case, it's awkward and (if there are a lot of these), slow.

    Instead, I'd suggest storing the parent object and its property in the array:

    const exampleDay = [
        {source: exercise.prehab, prop: "jointRotations"},
        // ...
    ];
    

    That way, you have the source object and the property the value comes from there at hand. Given the totals you're looking for, though, you may need to go further (but let's say you can assume the exercise part):

    const exampleDay = [
        {source: "prehab", prop: "jointRotations"},
        // ...
    ];
    

    (I haven't adequately allowed for the fact that strenghtIsolation has an extra level, but you can tweak as necessary.)

    When you need the value, use exercise[source][prop] to get it. When you want to find out how many times a given source object is used, it becomes much easier:

    let uses = Object.create(null);
    for (const {source} of exampleDay) {
        uses[source] = (uses[source] || 0) + 1;
    }
    uses = Object.entries(uses).map(([name, count]) => ({[name]: count}));