My suggestion is to create an object, then iterate over the data, create a key made from a combination of FromSize
and ToSize
(e.g. joined by some character) for each record, create an entry in the object for that key if it doesn't yet exist, set the property on the entry based on ClearityName
and Price
, and at the end output the Object.values
of your object.
Let's look at it step by step:
First, let's create an object which will temporarily hold our results as mapping from some key to some value:
const groupedData = {}
Then, let's iterate over our data using for of
:
for (const record of data) {
/* ... */
}
We could now access the values using record.FromSize
, etc. but the following code will be shorter if we destructure the properties at this point already, because we can take advantage of property shorthands (e.g. we can write { FromSize }
instead of { FromSize: record.FromSize }
):
for (const { FromSize, ToSize, ClearityName, Price } of data) {
/* ... */
}
For each record, we'll first build a key string from FromSize
and ToSize
so we can group by it. Since it's two values, we need to join them somehow. Since both are numbers, it's safe to just join them by a character like a comma so that FromSize: 54, ToSize: 51
will give you 54,51
:
const key = `${FromSize},${ToSize}`
Then if we create an entry in our grouped data object for the current key if it doesn't exist already. This entry will contain just the base properties of FromSize
and ToSize
because the others will be created individually afterwards:
groupedData[key] ??= { FromSize, ToSize }
The ??=
operator is relatively new in JavaScript. x ??= y
means the same as x = x ?? y
, with ??
being the nullish coalescing operator which evaluates to its right-hand-side argument if the left-hand-side argument is null
or undefined
, otherwise it will evaluate to the left-hand-side argument. Essentially, x ??= y
allows us to set x
to y
if it wasn't already set to something else before (more or less). If this gives you a syntax error, try the more verbose way of if (!groupedData[key]) groupedData[key] = { FromSize, ToSize }
instead.
Now that we have ensured that groupedData[key]
exists and has at least FromSize
and ToSize
set, we can set the new property that we need based on the ClearityName
, with a value of Price
:
groupedData[key][ClearityName] = Price
At this point, after our loop is completed, we have groupedData
as object with keys like 54,51
and values like { FromSize: 54, ToSize: 51, IF: 56, VS: 96, VSS: 26 }
, but you want an array of those values and are no longer interested in the keys at that point. You can get that using Object.values
:
const output = Object.values(groupedData)
Final result:
function getGroupedArray (data) {
const groupedData = {}
for (const { FromSize, ToSize, ClearityName, Price } of data) {
const key = `${FromSize},${ToSize}`
groupedData[key] ??= { FromSize, ToSize }
groupedData[key][ClearityName] = Price
}
return Object.values(groupedData)
}
// Let's test it:
const data = [
{ FromSize: 54, ToSize: 51, ClearityName: 'IF', Price: 56 },
{ FromSize: 54, ToSize: 51, ClearityName: 'VS', Price: 96 },
{ FromSize: 54, ToSize: 51, ClearityName: 'VSS', Price: 26 },
{ FromSize: 40, ToSize: 30, ClearityName: 'PF', Price: 36 },
{ FromSize: 40, ToSize: 30, ClearityName: 'IF', Price: 86 },
]
console.log(getGroupedArray(data))
.as-console-wrapper { max-height: 100% !important; top: 0; }
Click "Run code snippet" above to see it in action!
(Note: You can ignore the .as-console-wrapper
stuff here, that's just so that Stack Overflow will display the output in a nicer way.)
You can find more information about each of the functions used here by googling their names. If you are stuck understanding a certain piece of code I used here, just ask!