从对象数组创建自定义JSON

时间:2019-05-23 18:43:58

标签: javascript

在此处使用angularjs:

我有如下对象数组。在它下面只是显示2个对象的示例,但我可以超过2个。

[
 {
  "name": "John",
  "control": "1",
  "available": "true",  
  "comment": "n1",
  "value": "v1"
 },
 {
  "name": "Peter",  
  "control": "2",
  "available": "true",  
  "type": "integer",
  "comment": "n2",
  "value": "v2",
   "userOptions": [
   {
    "text": "Utah",
    "value": "UT"    
   },
   {
    "text": "New York",
    "value": "NY"
   }
  ]
 }
]

我想将json创建为:

"data":
{
  "John": 
   {
     "control": "1",
     "features": {
          "available": true
      },
      "value": "v1",
      "comment": "c1"
   } ,
 "Peter": 
   {
     "control": "2",
     "features": {
          "available": true,
          "userOptions": {
              "Utah": "UT",
              "New York": "NY",
          }
      },
      "value": "v2",
      "comment": "c2"
   }
}

因此,如果您看到json结构取决于控制键,则将添加一些额外的参数。 虽然某些键(如control,value,comment)保持不变。

任何人都可以分享如何创建上述json。我想在按钮事件中创建以上内容。

$scope.submit = function (isValid) {

if(isValid)
{
   $scope.data.filter(function (item, index) {

      for (var key in item) {

        }                   
   });
}

3 个答案:

答案 0 :(得分:2)

x$1

答案 1 :(得分:1)

首先,您应注意,第一个结构支持具有相同名称的多个用户,而第二个结构(需要一个)不支持。无论如何,如果您可以确定名称是唯一的,Array.reduce()可能是您的选择。

示例:

const input = [{"name":"John","control":"1","available":"true","comment":"n1","value":"v1"},{"name":"Peter","control":"2","available":"true","type":"integer","comment":"n2","value":"v2","userOptions":[{"text":"Utah","value":"UT"},{"text":"New York","value":"NY"}]}];

let res = input.reduce((acc, user) =>
{
    let {name, available, userOptions, ...others} = user;
    acc[name] = {...others, features: {available: JSON.parse(available)}};

    if (userOptions !== undefined)
    {
        acc[name].features.userOptions = {};

        userOptions.forEach(({text, value}) =>
        {
            acc[name].features.userOptions[text] = value;
        });
    }

    return acc;
}, {});

console.log(res);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

答案 2 :(得分:1)

我将从将其分解为较小的功能开始。我可能会得到这样的解决方案

const makeObject = kvs => 
  kvs .reduce ( (a, {text, value} ) => ( {...a, [text]: value} ), {})

const makeFeatures = ( {available, userOptions: uo, ...rest} ) =>
   ( {...rest, features: {
     ...( available ? {available} : {}),
     ...( uo ? {userOptions: makeObject (uo) } : {} )
   } } )

const transform = (people) => 
  people.reduce( (a, {name, ...rest} ) => ( {...a, [name]: makeFeatures ({...rest}) }), {})

const people = [{"available": "true", "comment": "n1", "control": "1", "name": "John", "value": "v1"}, {"available": "true", "comment": "n2", "control": "2", "name": "Peter", "type": "integer", "userOptions": [{"text": "Utah", "value": "UT"}, {"text": "New York", "value": "NY"}], "value": "v2"}]

console .log (
  transform (people)
)
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

思考过程

我将从外开始,首先像这样编写transform版本:

const transform = (people) => 
  people.reduce( (a, {name, ...rest} ) => ( {...a, [name]: {...rest} }), {})

只是将people转换为

{
  John: {...}
  Peter: {...}
}

和那些内部对象具有name以外的所有原始字段。

然后,我写一个makeFeatures的版本,看起来像这样:

const makeFeatures = ( {available, ...rest} ) =>
   ( {...rest, features: {available} } )

这样makeFeatures(people[1])会导致类似

{
  comment: "n1",
  control: "1",
  features: {
    available: "true"
  },
  value: "v1"
}

,对于people[2],它还将包括userOptionstype

然后我可以像这样调整transform

const transform = (people) => 
  people.reduce( (a, {name, ...rest} ) => ( {...a, [name]: makeFeatures({...rest}) }), {})

以便主函数将创建我们的基于名称的对象,并将available提取到每个人的特征中。

现在available在那,我们也需要处理userOptions。这可能稍微复杂一点,因为可能包含也可能不包含。因此,我像这样更改makeFeatures

const makeFeatures = ( {available, userOptions, ...rest} ) =>
   ( {...rest, features: {available, ...( userOptions ? {userOptions} : {} )} } )

其中包括userOptions inside个功能only if it's in the person object. Seeing this makes me wonder if可用的`有时也可能包括在内,为了安全起见,我将这样重写:

const makeFeatures = ( {available, userOptions, ...rest} ) =>
   ( {...rest, features: {
     ...( available ? {available} : {}),
     ...( userOptions ? {userOptions} : {} )
   } } )

因此,现在剩下要做的就是将userOptions对象从[{text, value}, {text2, value2}, ...]转换为{text: value, text2: value2, ...}。我们为此编写了一个新函数:

const convertOptions = userOptions => 
  userOptions .reduce ( (a, {text, value} ) => ( {...a, [text]: value} ), {})

,我们更改了makeFeatures来使用它:

const makeFeatures = ( {available, userOptions, ...rest} ) =>
   ( {...rest, features: {
     ...( available ? {available} : {}),
    ...( userOptions ? {userOptions: convertOptions (userOptions) } : {} )
   } } )

我们现在有了工作代码。它符合目前为止我们所拥有的规格,并且很容易看出我们如何适应新的要求。

但是我仍然想进行两次清理。首先,makeFeatures内对“ userOptions”的所有使用似乎都很混乱。我会添加这样的缩写:

const makeFeatures = ( {available, userOptions: uo, ...rest} ) =>
   ( {...rest, features: {
     ...( available ? {available} : {}),
     ...( uo ? {userOptions: convertOptions  (uo) } : {} )
   } } )

这是一个很小的考虑,有些人不赞成,但我觉得这样更容易。

第二,我们可以注意到convertOptions与选项无关。这是一个通用函数,它接受text / value对数组,并将它们转换为对象。因此,我将其重命名为makeObject,并可能将其从此块移至某些实用程序代码。

虽然听起来很长且涉及很多,但所有这些步骤总共花费了不到10分钟的时间。我在REPL中运行了它,并获得了所做更改的即时反馈,而且实际上并不复杂。在这里写下来花费了更多时间。