0

With an object array that looks like this:

[{
    "202201": {
        "WO": 900,
        "WS": 0,
        "SY": 0.915,
        "LY": 0.98,
        "CT": 75
    },
    "202202": {
        "WO": 300,
        "WS": 0,
        "SY": 0.915,
        "LY": 0.98,
        "CT": 73
    },
    "202203": {
        "WO": 350,
        "WS": 0,
        "SY": 0.915,
        "LY": 0.98,
        "CT": 68
    },
    "202204": {
        "WO": 400,
        "WS": 0,
        "SY": 0.915,
        "LY": 0.98,
        "CT": 77
    },
    "202205": {
        "WO": 300,
        "WS": 0,
        "SY": 0.915,
        "LY": 0.98,
        "CT": 67
    },
    "Product": "A",
    "Facility": "a-Facility"
},
{
    "202201": {
        "WO": 6665,
        "WS": 0,
        "SY": 0.903,
        "LY": 0.993,
        "CT": 73
    },
    "202202": {
        "WO": 5907,
        "WS": 0,
        "SY": 0.903,
        "LY": 0.993,
        "CT": 71
    },
    "202203": {
        "WO": 5893,
        "WS": 0,
        "SY": 0.903,
        "LY": 0.993,
        "CT": 74
    },
    "202204": {
        "WO": 5486,
        "WS": 0,
        "SY": 0.903,
        "LY": 0.993,
        "CT": 67
    },
    "202205": {
        "WO": 5448,
        "WS": 0,
        "SY": 0.903,
        "LY": 0.993,
        "CT": 69
    },
    "Product": "B",
    "Facility": "b-Facility"
}]

I am attempting to find the maximum "CT" (or cycle time) for all products on a production line across all facilities. In the example above, it would be 77.

The closest (and most modern) example I can find that comes close looks like this:Math.max(...array.map(o => o.y)) and comes from this question about the max in an array of objects, but doesn't quite get into an array of objects and all numeric properties of each object.

I assume there's a way to map, not only the array of objects, but the object properties which have a property of "CT" (and replace "undefined" with 0) in order to arrive at the max of 77. I will continue investigating as I wait for support.

It's a typescript application, but a javascript answer will work for me, too.

PROGRESS:

I am also hoping for something more sophisticated than a double for loop, so if you can beat these options, I'll be super happy with it:

numbers = [];
data.forEach(d => {
    numbers = numbers.concat(Object.keys(d).map(p => d[p].CT ? d[p].CT : 0));
})

maxCycle = Math.max(...numbers);
data.forEach(d => {
    for (const w in d) {
        maxCycle = maxCycle < d[w]['CT'] ? d[w]['CT'] : maxCycle;
    }
});
Csworen
  • 19
  • 6

2 Answers2

1
const maxValue = data.reduce((acc, current) => {
    for(item of Object.values(current)) {
        if(typeof(item) === 'object') {
            for(key in item) if(key === 'CT' && item[key] > acc) acc = item[key];
        }
    }
    return acc;    
}, 0);

The short version of this one is

const maxValue = data.reduce((acc, dataItem) => {
    for(item of Object.values(dataItem)) if(typeof(item) === 'object') for(key in item) if(key === 'CT' && item[key] > acc) acc = item[key];
    return acc;    
}, 0);

[Updated] More Optimized version

const maxValue = data.reduce((acc, current) => {
    for(item of Object.values(current)) if(item['CT'] > acc) acc = item['CT'];
    return acc;    
}, 0);

Hope this helps!

Asad Mahmood
  • 188
  • 1
  • 10
  • I already know we have an array of objects with objects as properties, so that validation is unnecessary. Also, iterating through the properties to find "CT" is unnecessary. The validation can be shortened to `if (item['CT'] && item['CT'] > acc)` to cut out an additional loop. – Csworen Sep 16 '22 at 18:59
1

You can use Array.flatMap and then take a max out of it.

This is a oneliner that should work:

Math.max(...arr.flatMap(i => Object.values(i)).flatMap(obj => obj.CT || -Infinity))

We need 2 flatMap as first we're taking the values of the objects and then we access the CT property of those objects.

Also -Infinity is a better option than 0, as you may have only negative values.

const arr = [{
    "202201": {
      "WO": 900,
      "WS": 0,
      "SY": 0.915,
      "LY": 0.98,
      "CT": 75
    },
    "202202": {
      "WO": 300,
      "WS": 0,
      "SY": 0.915,
      "LY": 0.98,
      "CT": 73
    },
    "202203": {
      "WO": 350,
      "WS": 0,
      "SY": 0.915,
      "LY": 0.98,
      "CT": 68
    },
    "202204": {
      "WO": 400,
      "WS": 0,
      "SY": 0.915,
      "LY": 0.98,
      "CT": 77
    },
    "202205": {
      "WO": 300,
      "WS": 0,
      "SY": 0.915,
      "LY": 0.98,
      "CT": 67
    },
    "Product": "A",
    "Facility": "a-Facility"
  },
  {
    "202201": {
      "WO": 6665,
      "WS": 0,
      "SY": 0.903,
      "LY": 0.993,
      "CT": 73
    },
    "202202": {
      "WO": 5907,
      "WS": 0,
      "SY": 0.903,
      "LY": 0.993,
      "CT": 71
    },
    "202203": {
      "WO": 5893,
      "WS": 0,
      "SY": 0.903,
      "LY": 0.993,
      "CT": 74
    },
    "202204": {
      "WO": 5486,
      "WS": 0,
      "SY": 0.903,
      "LY": 0.993,
      "CT": 67
    },
    "202205": {
      "WO": 5448,
      "WS": 0,
      "SY": 0.903,
      "LY": 0.993,
      "CT": 69
    },
    "Product": "B",
    "Facility": "b-Facility"
  }
]

console.log(Math.max(...arr.flatMap(i => Object.values(i)).flatMap(obj => obj.CT || -Infinity)))
Radu Diță
  • 13,476
  • 2
  • 30
  • 34
  • I disagree with negative time to cycle a product through a machine. I will run time trials against my live data and get back to you. It does look very modern, though. I've not heard of flatMap before. Thanks! – Csworen Sep 17 '22 at 04:35
  • You should never trust user input, no matter what your domain is. – Radu Diță Sep 17 '22 at 13:53
  • This isn't user input. It's validated data coming from the database. We validate during input and this is for analysis post-insertion. – Csworen Sep 17 '22 at 21:42