1

I need to transform from one schema to another. Is there any way of achieving this without doing a for loop?

Original data

[
  {
    "browser": "Chrome",
    "count": 73,
    "verdict": "detected"
  },
  {
    "browser": "Opera",
    "count": 3,
    "verdict": "detected"
  },
  {
    "browser": "Chrome",
    "count": 3,
    "verdict": "blocked"
  },
  {
    "browser": "Edge",
    "count": 1,
    "verdict": "detected"
  }
]

Transformed data

[
  {
    "browser": "Chrome",
    "detected":73,
    "blocked":3
  },
  {
    "browser": "Opera",
    "detected": 3,
    "blocked": 0
  },
  {
    "browser": "Edge",
    "detected": 1,
    "blocked": 0
  }
]
realPro
  • 1,713
  • 3
  • 22
  • 34
  • Why not use an object for the result? `{ Chrome: { ... }, Opera: { ... }, ... }` – kelsny Oct 25 '22 at 19:39
  • 1
    Get familiar with [how to access and process objects, arrays, or JSON](/q/11922383/4642212), and how to create [objects](//developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Object_initializer), and use the static and instance methods of [`Object`](//developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object#Static_methods) and [`Array`](//developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array#Static_methods). – Sebastian Simon Oct 25 '22 at 19:44

2 Answers2

2

I'd create a temporary map, so it can be accessed by its keys.
Then you can iterate the elements and update the temp map:

const initial = [{
    "browser": "Chrome",
    "count": 73,
    "verdict": "detected"
  },
  {
    "browser": "Opera",
    "count": 3,
    "verdict": "detected"
  },
  {
    "browser": "Chrome",
    "count": 3,
    "verdict": "blocked"
  },
  {
    "browser": "Edge",
    "count": 1,
    "verdict": "detected"
  }
];

const defaultValues = {
  detected: 0,
  blocked: 0
};
const ans = initial.reduce((acc, element) => {
  const {
    browser,
    verdict,
    count
  } = element;
  acc[browser] = {
    browser,
    ...(acc[browser] || defaultValues),
    [verdict]: count,
  };
  return acc;
}, {});

console.log(Object.values(ans));
GalAbra
  • 5,048
  • 4
  • 23
  • 42
2

Group them by the browser as a unique key, then the result is as easy as getting the values in the object.

const data=[{"browser":"Chrome","count":73,"verdict":"detected"},{"browser":"Opera","count":3,"verdict":"detected"},{"browser":"Chrome","count":3,"verdict":"blocked"},{"browser":"Edge","count":1,"verdict":"detected"}];

const grouped = data.reduce((o, { browser, count, verdict }) => {
    // If it's not in the map yet, add it as an empty entry
    if (!(browser in o)) o[browser] = { browser, detected: 0, blocked: 0 };
    
    // By now, it must be in the map, so it's as easy as adding the count to the verdict
    o[browser][verdict] += count;

    // Return modified map for the next iteration
    return o;
}, {});

const result = Object.values(grouped); // Get the values of the map

console.log(result); // Done!
.as-console-wrapper { max-height: 100% !important; top: 0; }

See destructuring if you're wondering about what (o, { browser, count, verdict }) => is doing, and the in operator for checking if a key exists in an object.

kelsny
  • 23,009
  • 3
  • 19
  • 48