繁体   English   中英

如何通过分组密钥将 json 转换为 javascript object

[英]How to convert json into a javascript object, with grouping a key

我有一个 json 如下所示

[{"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}]

为了更好地说明它,它看起来像这样

在此处输入图像描述

问题:如何将其转换为以下格式 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,
    },
  ],
}

如您所见,行数据被分组到资产 class 中。 所以,我不知道如何循环以获得预期的 json。 预期的 json output 是手写的,所以它不会加起来就是一个完整的。 但是我显示的格式是有效的。

// 解析 JSON

const objectList = JSON.parse(json);

// 创建一个 function 来分组和 select 数据

function groupDataByAssetClass(objectList: object[], assetClass: string) {
    const groupedList = objectList.filter(obj => obj.AssetClass === assetClass);
    return groupedList.map(obj => 
        delete obj.AssetClass;
        return obj;
    )
}

// 查找每个类别的项目

const macroItems = groupDataByAssetClass("Macro");
const equityItems = groupDataByAssetClass("Equity")
...

// 将所有列表合并为一个 object

const final = {
    Macro: macroItems,
    Equity: equityItems,
    ...
}

要解决这个问题,您需要执行 2 个操作 - 解析 json 和组对象。 一个简单的方法是:

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;
 }

但是,这不会从结果对象中删除 groupingKey。 如果你真的需要这个,使用下面的代码:

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;
 }

这样做的关键很简单,只需使用 hasOwnProperty 来检查您是否已经拥有该“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)

回答

您想通过对象之间的一些共同属性对数组进行分类。 将来可以使用Array.prototype.group完成,但现在最好使用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}

但是您还想delete元素分组所依据的属性。 只需在分类后遍历它们即可删除该属性:

 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}

不错的选择

如果您希望将所有这些逻辑隐藏在一个简单的 function 调用后面,您可能想看看Shmyhelskyi回答

使用Array.group

如果Array.prototype.group已经发布,那么你的代码最终会是这样的:

 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}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM