【问题标题】:JavaScript: Change Json data array into new formatJavaScript:将 Json 数据数组更改为新格式
【发布时间】:2020-04-14 08:30:23
【问题描述】:

我正在尝试处理需要以多种方式更改的 json 数据。

我当前的 json 数据如下:

{
  "file1": {
    "function1": {
      "calls": {
        "105:4": {
          "file": "file2",
          "function": "function5"
        },
        "106:4": {
          "file": "file2",
          "function": "function6"
        }
      },
      "lines1": {
        "123": "102:0",
        "456": "105:8"
      },
      "lines2": {
        "102:0": [
          "102:0"
        ],
        "105:4": [
          "106:4",
          "107:1"
        ],
        "106:4": [
          "107:1"
        ]
      }
    }
  }
}

但我希望数据如下:

{
  "name": "program",
  "children": [
    {
      "name": "file1",
      "children": [
        {
          "name": "function1",
          "calls": [
            {
              "line": 105,
              "file": "file2",
              "function": "function5"
            },
            {
              "line": 106,
              "file": "file2",
              "function": "function6"
            }
          ],
          "lines1": [
            102,
            105
          ],
          "lines2": [
            [
              102,
              102
            ],
            [
              105,
              106,
              107
            ],
            [
              106,
              107
            ]
          ],
          "group": 1
        }
      ],
      "group": 1
    }
  ],
  "group": 0
}

这里,文件和函数的数量更多。名字的值是用户定义的。组信息取决于父子。每个文件将有一个组升序组号,文件内的所有函数也将具有相同的组号。对于行的值,取 : 之前的第一部分(104:4 变为 104)。

到目前为止,我已尝试使用以下代码,该代码不完整且未正确处理组信息。

function build(data) {
    return Object.entries(data).reduce((r, [key, value], idx) => {
      const obj = {
        name: 'program',
        children: [],
        group: 0,
        lines: []
      }

      if (key !== 'lines2) {
        obj.name = key;
        obj.children = build(value)
          if(!(key.includes(":")))
          obj.group = idx + 1;
      } else {
        if (!obj.lines) obj.lines = [];
        Object.entries(value).forEach(([k, v]) => {
          obj.lines.push([k, ...v].map(e => e.split(':').shift()))
        })
      }

      r.push(obj)
      return r;
    }, [])
  }

  const result = build(data);
  console.log(result);

如果您能帮助我,我将不胜感激。提前感谢您的宝贵时间。

【问题讨论】:

    标签: javascript arrays json object mapping


    【解决方案1】:

    假设您的输入结构始终如您的问题所示(即不需要“安全检查”等),那么您可以使用Object.entries()Array.map() 和@ 的组合来解决此问题987654323@如下图。

    有关如何实现这一点的详细信息,请参阅此代码 sn-p 中的内联文档:

    function transformData(data, programName) {
    
      /* Define local parse helper to extract number from NUMBER:STRING format */    
      const parseHelper = (str) => Number.parseInt(str.split(':')[0]);
          
      /* Define local parse helper to extract group number from STRINGNUMBER 
      format */    
      const parseGroup = (str) => Number.parseInt(str.replace(/^[a-z]+/,""))
          
      /* Create a root object with specified program name */
      return {
        name : programName,
        
        /* Iterate each file name and object entry of input */
        children : Object.entries(input).map(([fileName, fileObject]) => {
    
          /* Iterate function name and object of current file object */
          const fileChildren = Object.entries(fileObject)
            .map(([functionName, functionObject]) => {
    
            /* Iterate function name and object of current file object */
            const lines = Object.entries(functionObject)
              .reduce((target, [functionKey, functionValue]) => {
    
                if(functionKey === "calls") {
    
                  /* If function key is calls, interpret this value as data to be
                  transformed to desired calls object shape */
                  const calls = Object.entries(functionValue)
                    .map(([callKey, callObject]) => {
    
                    return {
                      line : parseHelper(callKey),
                      file : callObject['file'],
                      function : callObject['function']
                    }
                  });
                  
                  /* Inject calls object into lines result */
                  return {
                    ...target,
                    calls
                  };
                }
                else {
    
                  /* Otherwise, interpret this value as data to be transformed to 
                     desired lines object shape */
                  const lineValues = Object.entries(functionValue)
                    .map(([key, value]) => {
    
                    /* If value is an array, map key/value pair to a nested array
                       in resulting linesValues array */
                    return Array.isArray(value) ? [key, ...value]
                     .map(parseHelper) : parseHelper(value)
                  })
    
                  /* Inject line values into function key of result */
                  return {
                    ...target,
                    [functionKey] : lineValues
                  }
                }
    
            }, {});
            
            /* Inject lines into function result */
            return {
              name : functionName,
              ...lines,
              group : parseGroup(functionName)
            }
          });
    
          /* Map file object to name/children pairing */
          return { 
            name : fileName,
            children : fileChildren,
              group : parseGroup(fileName)
          }
        }),
        
        group : 0
      }
    }
    
    const input = {
      "file1": {
        "function1": {
          "calls": {
            "105:4": {
              "file": "file2",
              "function": "function5"
            },
            "106:4": {
              "file": "file2",
              "function": "function6"
            }
          },
          "lines1": {
            "123": "102:0",
            "456": "105:8"
          },
          "lines2": {
            "102:0": [
              "102:0"
            ],
            "105:4": [
              "106:4",
              "107:1"
            ],
            "106:4": [
              "107:1"
            ]
          }
        }
      }
    };
    
    console.log(transformData(input, "program"))

    希望有帮助!

    【讨论】:

    • 非常感谢!!但是组信息不存在:(
    • 不客气 - 很抱歉错过了这一点,刚刚更新了答案。这有帮助吗?
    • 我很抱歉。 json 输出是正确的,但这个新结构不适用于我现有的 d3 代码。它显示以下错误:Argument of type '{ name: string;孩子:{组:号码;名称:字符串; }[];组:号码; }[]' 不可分配给“只读字符串 []”类型的参数。键入'{名称:字符串;孩子:{组:号码;名称:字符串; }[];组:号码; }' 不可分配给类型“字符串”。你能帮帮我吗? :(
    • 我只是想通过 const colorScale = d3.scaleOrdinal() .domain(data.children) .range(d3.schemeCategory10);
    • 你能用 D3 代码发布一个新问题并给我发一个链接吗?
    猜你喜欢
    • 2020-05-31
    • 2016-01-18
    • 2019-09-07
    • 2014-05-03
    • 1970-01-01
    • 2015-05-29
    • 2017-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多