有效地重命名/重新映射对象数组中的 javascript/json 对象键 [英] Efficiently rename/re-map javascript/json object keys within array of objects

查看:27
本文介绍了有效地重命名/重新映射对象数组中的 javascript/json 对象键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些像这样的结构化 JSON 数据.让我们假设这是可以互换的,通过 JSON.parse():

<预><代码>[{"title": "菠萝",uid":ab982d34c98f"},{"title": "胡萝卜","uid": "6f12e6ba45ec"}]

我需要它看起来像这样,将 title 重新映射到 name,并将 uid 重新映射到 id结果:

<预><代码>[{"name": "菠萝",id":ab982d34c98f"},{"name": "胡萝卜","id": "6f12e6ba45ec"}]

最明显的做法是这样的:

str = '[{"title": "pineapple","uid": "ab982d34c98f"},{"title": "carrots", "uid": "6f12e6ba45ec"}]';var arr = JSON.parse(str);for (var i = 0; i<arr.length; i++) {arr[i].name = arr[i].title;arr[i].id = arr[i].uid;删除 arr[i].title;删除 arr[i].uid;}

str = '[{"title": "pineapple","uid": "ab982d34c98f"},{"title": "carrots", "uid": "6f12e6ba45ec"}]';var arr = JSON.parse(str);for (var i = 0; i<arr.length; i++) {arr[i].name = arr[i].title;arr[i].id = arr[i].uid;删除 arr[i].title;删除 arr[i].uid;}$('body').append("<pre>"+JSON.stringify(arr, undefined, 4)+"</pre>");

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

...或者使用更复杂的东西(虽然不是更有效),比如 这个.

这一切都很好,但如果数组中有 200,000 个对象呢?这是大量的处理开销.

是否有更有效的方法来重新映射键名?可能不循环遍历整个对象数组?如果您的方法更有效,请提供证明/参考.

解决方案

正如我在评论中已经提到的,如果您可以对对象的值做出某些假设,则可以使用正则表达式来替换键,例如例子:

str = str.replace(/"title":/g, '"name":');

它不是那么干净",但它可以更快地完成工作.

<小时>

如果您无论如何都必须解析 JSON,则更结构化的方法是 reviver 函数传递给 JSON.parse ,您可能能够避免对数组进行额外的传递.不过,这可能取决于引擎如何实现 JSON.parse(也许他们首先解析整个字符串,然后使用 reviver 函数进行第二次传递,在这种情况下,您将不会获得任何优势).

var arr = JSON.parse(str, function(prop, value) {开关(道具){案例标题":this.name = 值;返回;案例uid":this.id = 值;返回;默认:返回值;}});

<小时>

基准测试,使用下面的 Node.js 脚本测试 3 次:

1389822740739:开始正则表达式重命名测试1389822740761:正则表达式重命名完成//22ms, 22ms, 21ms1389822740762:在 for 循环测试中开始解析和重新映射1389822740831:For 循环重映射完成//69ms, 68ms, 68ms1389822740831:开始reviver功能测试1389822740893:齐心协力功能完成//62ms, 61ms, 60ms

看起来好像正则表达式(在这种情况下)是最有效的,但是 尝试使用正则表达式解析 JSON 时要小心.

<小时>

测试脚本,加载 100,230 行 OP 的示例 JSON:

fs = require('fs');fs.readFile('test.json', 'utf8', function (err, data) {如果(错误){返回 console.log(err);}console.log(new Date().getTime() + ": Beginning regex rename test");var str = data.replace(/"title":/g, '"name":');str = str.replace(/"uid":/g, '"id":');JSON.parse(str);console.log(new Date().getTime() + ": Regex 重命名完成");console.log(new Date().getTime() + ": 开始解析并重新映射 for 循环测试");var arr = JSON.parse(data);for (var i = 0; i < arr.length; i++) {arr[i].name = arr[i].title;arr[i].id = arr[i].uid;删除 arr[i].title;删除 arr[i].uid;}console.log(new Date().getTime() + ": For 循环重映射完成");console.log(new Date().getTime() + ": Beginning reviver function test");var arr = JSON.parse(data, function (prop, value) {开关(道具){案例标题":this.name = 值;返回;案例uid":this.id = 值;返回;默认:返回值;}});console.log(new Date().getTime() + ": Reviver 函数完成");});

I have some structured JSON data like so. Let's assume this is interchangeable, via JSON.parse():

[
    {
        "title": "pineapple",
        "uid": "ab982d34c98f"
    },
    {
        "title": "carrots",
        "uid": "6f12e6ba45ec"
    }
]

I need it to look like this, remapping title to name, and uid to id with the result:

[
    {
        "name": "pineapple",
        "id": "ab982d34c98f"
    },
    {
        "name": "carrots",
        "id": "6f12e6ba45ec"
    }
]

The most obvious way of doing it is like this:

str = '[{"title": "pineapple","uid": "ab982d34c98f"},{"title": "carrots", "uid": "6f12e6ba45ec"}]';

var arr = JSON.parse(str);
for (var i = 0; i<arr.length; i++) {
    arr[i].name = arr[i].title;
    arr[i].id = arr[i].uid;
    delete arr[i].title;
    delete arr[i].uid;
}

str = '[{"title": "pineapple","uid": "ab982d34c98f"},{"title": "carrots",    		"uid": "6f12e6ba45ec"}]';

var arr = JSON.parse(str);
for (var i = 0; i<arr.length; i++) {
    arr[i].name = arr[i].title;
    arr[i].id = arr[i].uid;
    delete arr[i].title;
    delete arr[i].uid;
}

$('body').append("<pre>"+JSON.stringify(arr, undefined, 4)+"</pre>");

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

...or using something more complex (albeit not more efficient) like this.

This is all fine and dandy, but what if there were 200,000 objects in the array? This is a lot of processing overhead.

Is there a more efficient way to remap a key name? Possibly without looping through the entire array of objects? If your method is more efficient, please provide proof/references.

解决方案

As I already mentioned in the comments, if you can make certain assumptions about the values of the objects, you could use a regular expression to replace the keys, for example:

str = str.replace(/"title":/g, '"name":');

It's not as "clean", but it might get the job done faster.


If you have to parse the JSON anyway, a more structured approach would be to pass a reviver function to JSON.parse and you might be able to avoid an additional pass over the array. This probably depends on how engine implement JSON.parse though (maybe they parse the whole string first and then make a second pass with the reviver function, in which case you wouldn't get any advantage).

var arr = JSON.parse(str, function(prop, value) {
   switch(prop) {
     case "title":
        this.name = value;
        return;
     case "uid":
        this.id = value;
        return;
     default:
        return value;
   }
});


Benchmarks, using the Node.js script below to test 3 times:

1389822740739: Beginning regex rename test
1389822740761: Regex rename complete
// 22ms, 22ms, 21ms
1389822740762: Beginning parse and remap in for loop test
1389822740831: For loop remap complete
// 69ms, 68ms, 68ms
1389822740831: Beginning reviver function test
1389822740893: Reviver function complete
// 62ms, 61ms, 60ms

It appears as if the regex (in this case) is the most efficient, but be careful when trying to parse JSON with regular expressions.


Test script, loading 100,230 lines of the OP's sample JSON:

fs = require('fs');
fs.readFile('test.json', 'utf8', function (err, data) {
    if (err) {
        return console.log(err);
    }
    console.log(new Date().getTime() + ": Beginning regex rename test");
    var str = data.replace(/"title":/g, '"name":');
    str = str.replace(/"uid":/g, '"id":');
    JSON.parse(str);
    console.log(new Date().getTime() + ": Regex rename complete");
    console.log(new Date().getTime() + ": Beginning parse and remap in for loop test");
    var arr = JSON.parse(data);
    for (var i = 0; i < arr.length; i++) {
        arr[i].name = arr[i].title;
        arr[i].id = arr[i].uid;
        delete arr[i].title;
        delete arr[i].uid;
    }
    console.log(new Date().getTime() + ": For loop remap complete");
    console.log(new Date().getTime() + ": Beginning reviver function test");
    var arr = JSON.parse(data, function (prop, value) {
        switch (prop) {
            case "title":
                this.name = value;
                return;
            case "uid":
                this.id = value;
                return;
            default:
                return value;
        }
    });
    console.log(new Date().getTime() + ": Reviver function complete");
});

这篇关于有效地重命名/重新映射对象数组中的 javascript/json 对象键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆