在 Javascript 中重新格式化 JSON 数据的优雅、简洁的方法?

Elegant, concise way to reformat JSON data in Javascript?

我从旧的数据库查询中收到以下格式的 JSON 结果消息,我目前无法更改:

{
  "vsm1": "2429",
  "vsm2": "2488",
  "vsm3": "1968",
  "vsm4": "",
  "vsm5": "",
  "vsm6": "",
  "vsm7": "",
  "vsm8": "",
  "vsm9": "",
  "vsm10": "",
  "color1": "5",
  "color2": "4",
  "color3": "4",
  "color4": "0",
  "color5": "0",
  "color6": "0",
  "color7": "0",
  "color8": "0",
  "color9": "0", 
  "color10": "0",
  "p1mtime": "1549296004",
  "p2mtime": "1549296009",
  "p3mtime": "1549296014",
  "p4mtime": "",
  "p5mtime": "",
  "p6mtime": "",
  "p7mtime": "",
  "p8mtime": "",
  "p9mtime": "",
  "p10mtime": "",
  "inch1": "",
  "inch2": "",
  "inch3": "",
  "inch4": "",
  "inch5": "",
  "inch6": "",
  "inch7": "",
  "inch8": "",
  "inch9": "",
  "inch10": "" 

}

我想将其重新格式化为更有用的对象,如下所示:

{ id: 1, vsm: 2429, color: 5, pmtime: 1549296004, inch: 0  }
{ id: 2, vsm: 2488, color: 4, pmtime: 1549296009, inch: 0  }
{ id: 3, vsm: 1968, color: 4, pmtime: 1549296014, inch: 0  }

...等等。

输入数据目前限制为每个 'section' 十个(vsm1、vsm2、...vsm10、color1、color2、...color10 等),因此是某种静态循环每个部分的十个元素是我的开始方式,但看起来相当丑陋,而且肯定不灵活。

如果数据超过 10 个元素或下降到仅 3 个(由于缺少数据或数据被删减),一个能够处理每个部分中 n 个元素的智能代码片段会更好。

我正在考虑使用 .forEach() 的方法,但不可否认我的 JSON / 对象操作技能很差,所以我求助于社区,希望有人能指出我在正确的方向或知道一个很酷,紧 routine/function 实现我正在寻找的东西。提前感谢您的任何见解。

您可以获取一个包含 运行 数字占位符的所需键的数组,然后构建新对象并将它们推送到结果集。

var data = { vsm1: "2429", vsm2: "2488", vsm3: "1968", vsm4: "", vsm5: "", vsm6: "", vsm7: "", vsm8: "", vsm9: "", vsm10: "", color1: "5", color2: "4", color3: "4", color4: "0", color5: "0", color6: "0", color7: "0", color8: "0", color9: "0", color10: "0", p1mtime: "1549296004", p2mtime: "1549296009", p3mtime: "1549296014", p4mtime: "", p5mtime: "", p6mtime: "", p7mtime: "", p8mtime: "", p9mtime: "", p10mtime: "", inch1: "", inch2: "", inch3: "", inch4: "", inch5: "", inch6: "", inch7: "", inch8: "", inch9: "", inch10: "" },
    keys = ['vsm*', 'color*', 'p*mtime', 'inch*'],
    result = [],
    id = 1;

while (keys[0].replace('*', id) in data) {
    result.push(Object.assign(
        { id },
        ...keys.map(k => ({ [k.replace('*', '')]: +data[k.replace('*', id)]  || 0 }))
    ));
    id++;
}

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

template literals

var data = { vsm1: "2429", vsm2: "2488", vsm3: "1968", vsm4: "", vsm5: "", vsm6: "", vsm7: "", vsm8: "", vsm9: "", vsm10: "", color1: "5", color2: "4", color3: "4", color4: "0", color5: "0", color6: "0", color7: "0", color8: "0", color9: "0", color10: "0", p1mtime: "1549296004", p2mtime: "1549296009", p3mtime: "1549296014", p4mtime: "", p5mtime: "", p6mtime: "", p7mtime: "", p8mtime: "", p9mtime: "", p10mtime: "", inch1: "", inch2: "", inch3: "", inch4: "", inch5: "", inch6: "", inch7: "", inch8: "", inch9: "", inch10: "" },
    templates = [id => `vsm${id}`, id => `color${id}`, id => `p${id}mtime`, id => `inch${id}`],
    result = [],
    id = 1;

while (templates[0](id) in data) {
    result.push(Object.assign(
        { id },
        ...templates.map(t => ({ [t('')]: +data[t(id)]  || 0 }))
    ));
    id++;
}

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

试试这个,用 oldObject 你想要清理的对象:

var cleanedObject = {};
for (let [key, value] of Object.entries(oldObject)) {
  let index = key.match('[0-9]+');
  cleanedObject[index] = cleanedObject[index] || {};
  cleanedObject[index][key.replace(index, '')] = value;
}

结果将是一个对象,其中 cleanedObject['1'] = { vsm: 2429, color: 5, pmtime: 1549296004, inch: '' },依此类推。

此解决方案与 Nina Sholz 的解决方案具有不同的灵活性。 Nina's 允许您匹配任何样式的包含数字的键。但它也需要您添加一个模板才能这样做。我的将处理任何仅包含单个 运行 数字但没有更复杂的键。但是它不需要你做任何事情来处理这样的模板。

const reformat = data => Object.values(Object.keys(data)
  .reduce(
    (a, k, i, _, d = k.match(/\d+/)[0])  => ({
      ...a, 
      [d]: {...(a[d] || {id: Number(d)}), [k.replace(/\d+/, '')]: data[k]}
    }), {})).sort((a, b) => a.id - b.id)

const data = {"vsm1":"2429","vsm2":"2488","vsm3":"1968","vsm4":"","vsm5":"","vsm6":"","vsm7":"","vsm8":"","vsm9":"","vsm10":"","color1":"5","color2":"4","color3":"4","color4":"0","color5":"0","color6":"0","color7":"0","color8":"0","color9":"0","color10":"0","p1mtime":"1549296004","p2mtime":"1549296009","p3mtime":"1549296014","p4mtime":"","p5mtime":"","p6mtime":"","p7mtime":"","p8mtime":"","p9mtime":"","p10mtime":"","inch1":"","inch2":"","inch3":"","inch4":"","inch5":"","inch6":"","inch7":"","inch8":"","inch9":"","inch10":""}

console.log(reformat(data))

我不知道您是否需要任何一种灵活性,但这些都是有趣的替代方案。

我现在看到我的答案与 Ninas 基本相同,之前没有见过模板,所以这很酷,但鉴于这是我第一次尝试在这里回答一些问题,我将分享无论如何。

作为 Ninas,这可以处理任何长度的数据。

const data = {"vsm1": "2429",
  "vsm2": "2488",
  "vsm3": "1968",
  "vsm4": "",
  "color1": "5",
  "color2": "4",
  "color3": "4",
  "color4": "0",
  "p1mtime": "1549296004",
  "p2mtime": "1549296009",
  "p3mtime": "1549296014",
  "p4mtime": "",
  "inch1": "",
  "inch2": "",
  "inch3": "",
  "inch4": "",
  };


const vsmRegex = new RegExp("(vsm\d)");
const keys = Object.keys(data);

const result = [];
let id= 1;

for(let i = 0; i < keys.length; i++) {
  if(keys[i].match(vsmRegex)) {
    let object = {
      id: id,
      vsm: Number(data[`vsm${id}`]) || 0,
      color: Number(data[`color${id}`]) || 0,
      pmtime: Number(data[`p${id}mtime`]) || 0,
      inch: Number(data[`inch${id}`]) || 0
    };
    result.push(object);
    id++;
  } else {
    break;
  }
}

console.log(result);