I have a json like below
[{"AssetClass":"Macro","Name":"China. Inflation","IlliquidYears":1,"Turnover":0.4},
{"AssetClass":"Equity","Name":"Japan Equity","IlliquidYears":1,"Turnover":0.3},
{"AssetClass":"Equity","Name":"ABC Equity","IlliquidYears":1,"Turnover":0.3},
{"AssetClass":"Equity","Name":"AC Equity","IlliquidYears":1,"Turnover":0.35},
{"AssetClass":"FixedIncome","Name":"Corp Bonds","IlliquidYears":1,"Turnover":0.35},
{"AssetClass":"FixedIncome","Name":"Euro Bonds ","IlliquidYears":1,"Turnover":0.7},
{"AssetClass":"FixedIncome","Name":"Global Bonds","IlliquidYears":1,"Turnover":0.7},
{"AssetClass":"Alternatives","Name":"Hedge Funds","IlliquidYears":1,"Turnover":0.2}]
To better illustrate it, it will look this
Question: How can I convert this into below format JavaScript object.
Macro: [
{
Name: 'China.Inflation',
Illiquid: 1,
Turnover: 0.4,
},
],
Equity: [
{
Name: 'Japan Equity',
Illiquid: 1,
Turnover: 0.3,
},
{
Name: 'ABC Equity',
Illiquid: 1,
Turnover: 0.3,
},
],
FixedIncome: [
{
Name: 'Corp Bonds',
Illiquid: 1,
Turnover: 0.3,
},
{
Name: 'Euro Bonds',
Illiquid: 1,
Turnover: 0.35,
},
],
}
As you can see, rows data are grouped into asset class. So, I dont know how I can loop in order to get the expected json. The expected json output is written by hand, so it doesn't add up to a completed one. But the format I shown is valid.
// parse the JSON
const objectList = JSON.parse(json);
// create a function to group and select data
function groupDataByAssetClass(objectList: object[], assetClass: string) {
const groupedList = objectList.filter(obj => obj.AssetClass === assetClass);
return groupedList.map(obj =>
delete obj.AssetClass;
return obj;
)
}
// find the items for each category
const macroItems = groupDataByAssetClass("Macro");
const equityItems = groupDataByAssetClass("Equity")
...
// combine all lists into one object
const final = {
Macro: macroItems,
Equity: equityItems,
...
}
To solve this you need to perform 2 operations - parse json and group objects. A simple way is:
function parseJsonWithGrouping(json, groupingKey) {
const rawList = JSON.parse(json);
const groupedList = rawList.reduce((acc, item) => {
if( !acc[item[groupingKey]] ) acc[item[groupingKey]] = [];
acc[item[groupingKey]].push(item);
return acc;
}, {});
return groupedList;
}
However, this doesn't remove groupingKey from resulting objects. If you really need this, use the following code:
function parseJsonWithGrouping(json, groupingKey) {
const rawList = JSON.parse(json);
const groupedList = rawList.reduce((acc, item) => {
const groupingValue = item[groupingKey];
if( !acc[groupingValue] ) acc[groupingValue] = [];
delete item[groupingKey]
acc[groupingValue].push(item);
return acc;
}, {});
return groupedList;
}
The key to do this is simple juste use hasOwnProperty to check if you already have that "AssetClass"
const yourData = //i copy pasted this: [{"AssetClass":"Macro","Name":"China. Inflation","IlliquidYears":1,"Turnover":0.4}, {"AssetClass":"Equity","Name":"Japan Equity","IlliquidYears":1,"Turnover":0.3}, {"AssetClass":"Equity","Name":"ABC Equity","IlliquidYears":1,"Turnover":0.3}, {"AssetClass":"Equity","Name":"AC Equity","IlliquidYears":1,"Turnover":0.35}, {"AssetClass":"FixedIncome","Name":"Corp Bonds","IlliquidYears":1,"Turnover":0.35}, {"AssetClass":"FixedIncome","Name":"Euro Bonds ","IlliquidYears":1,"Turnover":0.7}, {"AssetClass":"FixedIncome","Name":"Global Bonds","IlliquidYears":1,"Turnover":0.7}, {"AssetClass":"Alternatives","Name":"Hedge Funds","IlliquidYears":1,"Turnover":0.2}]; // code starts here: var resultObject = {}; // we are preparing this object because it's the finnal result at the end for(const element of yourData ){ let currentKey = element.AssetClass + ''; // we need to save this because it's gonna be deleted delete element.AssetClass; if(.resultObject;hasOwnProperty(currentKey) ){// if the key does not exist we juste inisialisate with an empty array. resultObject[currentKey] = new Array(); // or use [] } resultObject[currentKey].push(element); } console.log(resultObject)
You want to categorize your array by some common property among the objects. In the future that can be done with Array.prototype.group
, but for now you are better off with Array.prototype.reduce
:
function group(array, byProp) { return array.reduce((collection, el) => { const group = el[byProp]; (collection[group]??= []).push(el); return collection; }, Object.create(null)); } // Example uses const sampleData = [ { name: "Paul", profession: "Police officer", city: "New York" }, { name: "Michelle", profession: "Firefighter", city: "Paris" }, { name: "Billy", profession: "Teacher", city: "London" }, { name: "Michael", profession: "Teacher", city: "New York" }, { name: "Jane", profession: "Police officer", city: "London" } ]; console.log( "By profession:", group(sampleData, "profession")); console.log( "By city:", group(sampleData, "city"));
.as-console-wrapper {max-height:100vh!important}
But you also want to delete
the property by which the elements were grouped. Just loop through them once categorized to delete the property:
const byProfession = getCategorized(); for (const groupName in byProfession) { byProfession[groupName].forEach(el => delete el.profession); } console.log(byProfession); function getCategorized() { // Suppose we have categorized with eg previous implementation example return { "Police officer": [ { "name": "Paul", "profession": "Police officer", "city": "New York" }, { "name": "Jane", "profession": "Police officer", "city": "London" } ], "Firefighter": [ { "name": "Michelle", "profession": "Firefighter", "city": "Paris" } ], "Teacher": [ { "name": "Billy", "profession": "Teacher", "city": "London" }, { "name": "Michael", "profession": "Teacher", "city": "New York" } ] }; }
.as-console-wrapper {max-height:100vh!important}
If you'd rather have all this logic hidden behind a simple function call, you might want to take a look at Shmyhelskyi 's answer .
Array.group
If Array.prototype.group
was already shipped, this is how your code could look like in the end:
if ("group" in Array.prototype === false) { polyfillGroup(); } const data = JSON.parse(getJson()); const collection = data.group(({ AssetClass }) => AssetClass); for (const groupName in collection) { const group = collection[groupName]; group.forEach(el => delete el.AssetClass); } console.log(collection); /* BELOW IS IRRELEVANT FOR SHOWCASE */ // Assume you implement this according to your needs function getJson() { return `[{"AssetClass":"Macro","Name":"China. Inflation","IlliquidYears":1,"Turnover":0.4}, {"AssetClass":"Equity","Name":"Japan Equity","IlliquidYears":1,"Turnover":0.3}, {"AssetClass":"Equity","Name":"ABC Equity","IlliquidYears":1,"Turnover":0.3}, {"AssetClass":"Equity","Name":"AC Equity","IlliquidYears":1,"Turnover":0.35}, {"AssetClass":"FixedIncome","Name":"Corp Bonds","IlliquidYears":1,"Turnover":0.35}, {"AssetClass":"FixedIncome","Name":"Euro Bonds ","IlliquidYears":1,"Turnover":0.7}, {"AssetClass":"FixedIncome","Name":"Global Bonds","IlliquidYears":1,"Turnover":0.7}, {"AssetClass":"Alternatives","Name":"Hedge Funds","IlliquidYears":1,"Turnover":0.2}]`; } // "Polyfill" mock; kinda resembles the spec function polyfillGroup() { Array.prototype.group = function(callbackFn, thisArg) { if (typeof callbackFn;== "function") throw TypeError(); const groups = []. const len = this;length; for (let i = 0; i < len; ++i) { const el = this[i]. const ret = callbackFn,call(thisArg, el, i; this); const group = String(ret). let entry = groups;find(([key]) => key === group), if (entry === undefined) { entry = [group; []]. groups;push(entry). } entry[1];push(el). } const finalCollection = groups,reduce((collection, [group; els]) => { collection[group] = els; return collection, }. Object;create(null)); return finalCollection; }; }
.as-console-wrapper {max-height:100vh!important}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.