Thomas Fournet
Thomas Fournet

Reputation: 700

Javascript script optimization with map/reduce/filter

Here is my problem, I receive these kind of json data and I don't know in advance the keys (unknownProperty#) but the different objects in this data array have the same keys. What I need to do is to calculate the number of each level of alert (these levels are fixed). Here is what my end result should look like

var result = { unknownProperty1: { unknown: 0, ok: 2, warning: 0, ko: 1 },
  unknownProperty2: { unknown: 0, ok: 0, warning: 2, ko: 1 },
  unknownProperty3: { unknown: 3, ok: 0, warning: 0, ko: 0 },
  unknownProperty4: { unknown: 0, ok: 0, warning: 3, ko: 0 },
  unknownProperty5: { unknown: 0, ok: 0, warning: 2, ko: 1 } }

My script is working but I would like to know if there is any way to optimize/clean it with map/reduce/filter javascript function

const data = [
  {
    unknownProperty1: { alert: "ok", unusedItem1: "something" },
    unknownProperty2: { alert: "warning", unusedItem1: "something" },
    unknownProperty3: { alert: "unknown", unusedItem1: "something" },
    unknownProperty4: { alert: "warning", unusedItem1: "something" },
    unknownProperty5: { alert: "ko", unusedItem1: "something" }
  },
  {
    unknownProperty1: { alert: "ok", unusedItem1: "something" },
    unknownProperty2: { alert: "warning", unusedItem1: "something" },
    unknownProperty3: { alert: "unknown", unusedItem1: "something" },
    unknownProperty4: { alert: "warning", unusedItem1: "something" },
    unknownProperty5: { alert: "warning", unusedItem1: "something" }
  },
  {
    unknownProperty1: { alert: "ko", unusedItem1: "something" },
    unknownProperty2: { alert: "ko", unusedItem1: "something" },
    unknownProperty3: { alert: "unknown", unusedItem1: "something" },
    unknownProperty4: { alert: "warning", unusedItem1: "something" },
    unknownProperty5: { alert: "warning", unusedItem1: "something" }
  }
];

var result = new Object();
var dataKeys = data.map(function(element) {
  return Object.keys(element);
});
dataKeys[0].map(function(element) {
  result[element] = { unknown: 0, ok: 0, warning: 0, ko: 0 };
});
//At this point the result is like what we expect but no calculation has been made yet

//We then increment the right values
data.map(function(element) {
  for (var prop in element) {
    if (Object.prototype.hasOwnProperty.call(element, prop)) {
      // element correspond to the current object
      // prop corresponds to the name of the key, for example 'unknownProperty1'
      switch (element[prop].alert) {
        case "ok":
          result[prop].ok++;
          break;
        case "warning":
          result[prop].warning++;
          break;
        case "unknown":
          result[prop].unknown++;
          break;
        case "ko":
          result[prop].ko++;
          break;

        default:
          break;
      }
    }
  }
});
console.log(result);

Upvotes: 3

Views: 1475

Answers (3)

EugenSunic
EugenSunic

Reputation: 13703

Running late, but here is another example,

Full code (see console.log): https://stackblitz.com/edit/js-5rnwvv

Input data:

const data = [
  {
    unknownProperty1: { alert: "ok", unusedItem1: "something" },
    unknownProperty2: { alert: "warning", unusedItem1: "something" },
    unknownProperty3: { alert: "unknown", unusedItem1: "something" },
    unknownProperty4: { alert: "warning", unusedItem1: "something" },
    unknownProperty5: { alert: "ko", unusedItem1: "something" }
  },
  {
    unknownProperty1: { alert: "ok", unusedItem1: "something" },
    unknownProperty2: { alert: "warning", unusedItem1: "something" },
    unknownProperty3: { alert: "unknown", unusedItem1: "something" },
    unknownProperty4: { alert: "warning", unusedItem1: "something" },
    unknownProperty5: { alert: "warning", unusedItem1: "something" }
  },
  {
    unknownProperty1: { alert: "ko", unusedItem1: "something" },
    unknownProperty2: { alert: "ko", unusedItem1: "something" },
    unknownProperty3: { alert: "unknown", unusedItem1: "something" },
    unknownProperty4: { alert: "warning", unusedItem1: "something" },
    unknownProperty5: { alert: "warning", unusedItem1: "something" }
  }
];

Code for output data:

const a = data.reduce((acc, x, i) => {
  const keys = Object.keys(x);
  keys.forEach((key, j) => {
    const childKey = Object.keys(x[key])[0]; // only 'alert' key needed
    if (acc.hasOwnProperty(keys[j])) {
      // update existing key value pair
      ++acc[key][x[key][childKey]]
    } else {
      // add key value pair for the first time
      acc = {
        ...acc,
        [keys[j]]:
          ['unknown', 'warning', 'ko', 'ok'].reduce((ac, z) => ({ ...ac, [z]: x[key][childKey] === z ? 1 : 0 }), {})
      }
    }

  })
  return acc;

}, {})

Upvotes: 1

CertainPerformance
CertainPerformance

Reputation: 370689

Reduce into an object indexed by the unknownProperty_ keys, iterating over the inner objects and creating the appropriate key on the accumulator if it doesn't exist yet, and setting its value to { unknown: 0, ok: 0, warning: 0, ko: 0 }. Then, on each iteration over an unknownProperty object, just extract the alert and increment the a[key][alert]:

const data = [
  {
    unknownProperty1: { alert: "ok", unusedItem1: "something" },
    unknownProperty2: { alert: "warning", unusedItem1: "something" },
    unknownProperty3: { alert: "unknown", unusedItem1: "something" },
    unknownProperty4: { alert: "warning", unusedItem1: "something" },
    unknownProperty5: { alert: "ko", unusedItem1: "something" }
  },
  {
    unknownProperty1: { alert: "ok", unusedItem1: "something" },
    unknownProperty2: { alert: "warning", unusedItem1: "something" },
    unknownProperty3: { alert: "unknown", unusedItem1: "something" },
    unknownProperty4: { alert: "warning", unusedItem1: "something" },
    unknownProperty5: { alert: "warning", unusedItem1: "something" }
  },
  {
    unknownProperty1: { alert: "ko", unusedItem1: "something" },
    unknownProperty2: { alert: "ko", unusedItem1: "something" },
    unknownProperty3: { alert: "unknown", unusedItem1: "something" },
    unknownProperty4: { alert: "warning", unusedItem1: "something" },
    unknownProperty5: { alert: "warning", unusedItem1: "something" }
  }
];

const dataByProperty = data.reduce((a, obj) => {
  Object.entries(obj).forEach(([key, { alert }]) => {
    if (!a[key]) {
      a[key] = { unknown: 0, ok: 0, warning: 0, ko: 0 };
    }
    a[key][alert]++;
  });
  return a;
}, {});
console.log(dataByProperty);

Upvotes: 6

Ernesto Stifano
Ernesto Stifano

Reputation: 3130

Maybe a bit late, but this was my similar idea:

(NOTE: Avoid using let obj = new Object();, use let obj = {} instead)


const data = [
    {
        unknownProperty1: { alert: "ok", unusedItem1: "something" },
        unknownProperty2: { alert: "warning", unusedItem1: "something" },
        unknownProperty3: { alert: "unknown", unusedItem1: "something" },
        unknownProperty4: { alert: "warning", unusedItem1: "something" },
        unknownProperty5: { alert: "ko", unusedItem1: "something" }
    },
    {
        unknownProperty1: { alert: "ok", unusedItem1: "something" },
        unknownProperty2: { alert: "warning", unusedItem1: "something" },
        unknownProperty3: { alert: "unknown", unusedItem1: "something" },
        unknownProperty4: { alert: "warning", unusedItem1: "something" },
        unknownProperty5: { alert: "warning", unusedItem1: "something" }
    },
    {
        unknownProperty1: { alert: "ko", unusedItem1: "something" },
        unknownProperty2: { alert: "ko", unusedItem1: "something" },
        unknownProperty3: { alert: "unknown", unusedItem1: "something" },
        unknownProperty4: { alert: "warning", unusedItem1: "something" },
        unknownProperty5: { alert: "warning", unusedItem1: "something" }
    }
];

let result = data.reduce((acc, val) => {
    for (let i in val) {
        if (!val.hasOwnProperty(i)) {
            continue;
        }
        acc[i] || (acc[i] = {unknown: 0, ok: 0, warning: 0, ko: 0});
        acc[i][val[i].alert]++;
    }
    return (acc);
}, {});

console.log(result);

Upvotes: 1

Related Questions