简体   繁体   English

将对象属性添加到JSON对象中

[英]Adding object properties into a JSON object

I have a JSON object in this format. 我有这种格式的JSON对象。

[
    {
        "name": "schoolname",
        "line id": "0",
        "time": "4-5",
        "minage": "15",
        "maxage": "35"
    },
    {
        "name": "studentname1",
        "line id": "1",
        "class": "A"
    },
    {
        "name": "studentname2",
        "line id": "2",
        "class": "B"
    }
]

What I want to do 我想做的事

From a set of specified headers, get it from the "line id" : "0" and set it to the other items. 从一组指定的标题中,从"line id" : "0"获取它并将其设置为其他项目。

For Example: headers = ["time", "minage", "maxage"] 例如: headers = ["time", "minage", "maxage"]

I get these from the "line id" : "0" and give it to others like this. 我从"line id" : "0"得到这些"line id" : "0"并将其交给其他人。

[
    {
        "name": "schoolname",
        "line id": "0",
        "time": "4-5",
        "minage": "15",
        "maxage": "35"
    },
    {
        "name": "studentname1",
        "line id": "1",
        "class": "A",
        "time": "4-5",
        "minage": "15",
        "maxage": "35"
    },
    {
        "name": "studentname2",
        "line id": "2",
        "class": "B",
        "time": "4-5",
        "minage": "15",
        "maxage": "35"
    }
]

and then remove the element with "line id" : "0" , like this: 然后删除带有"line id" : "0"的元素,如下所示:

[
    {
        "name": "studentname1",
        "line id": "1",
        "class": "A",
        "time": "4-5",
        "minage": "15",
        "maxage": "35"
    },
    {
        "name": "studentname2",
        "line id": "2",
        "class": "B",
        "time": "4-5",
        "minage": "15",
        "maxage": "35"
    }
]

It is said that the 1st element would be a "line id" : "0" . 据说第一个元素是"line id" : "0"

What I've tried: 我尝试过的:

var headers = ["time", "minage", "maxage"]
var data = 
    [
        {
            "name": "schoolname",
            "line id": "0",
            "time": "4-5",
            "minage": "15",
            "maxage": "35"
        },
        {
            "name": "studentname1",
            "line id": "1",
            "class": "A"
        },
        {
            "name": "studentname2",
            "line id": "2",
            "class": "B"
        }
    ];

for(var i = 1; i < data.length; i++)//iterate over the data leaving the 1st line
{
    for(var j = 0; j < headers.length; j++)//add each header to the data lines
     {
        data[i][headers[j]] = data[0][headers[j]];
     }
}
data.splice(0,1);

Everything works fine and as intended. 一切正常,按预期工作。 Is there a way to reduce the time-complexity of this and make it more efficient. 有没有办法减少这种时间复杂性并使其更有效率。

This now has a time complexity of O(n * m). 现在这具有O(n * m)的时间复杂度。

Is there a way around of adding these few objects to all the elements? 有没有办法将这些少数对象添加到所有元素? As the key value pairs to be added for all the entries remain the same. 由于要为所有条目添加的键值对保持不变。

You can use Object.defineProperties like 您可以使用Object.defineProperties之类的

 var arr = [{ "name": "schoolname", "line id": "0", "time": "4-5", "minage": "15", "maxage": "35" }, { "name": "studentname1", "line id": "1", "class": "A" }, { "name": "studentname2", "line id": "2", "class": "B" }], headers = ["time", "minage", "maxage"]; function addHeaders(arr, headers) { var header = arr.splice(0, 1)[0], propObj = headers.reduce(function(acc, el) { acc[el] = { value: header[el], writable: true, enumerable: true }; return acc; }, {}); for (var i = 0, len = arr.length; i < len; i++) { Object.defineProperties(arr[i], propObj); } return arr; } document.getElementById('r').innerHTML = 'initial: ' + JSON.stringify(arr,null,2) + '<br/>'; document.getElementById('r').innerHTML += 'result: ' + JSON.stringify(addHeaders(arr, headers),null,2); 
 <pre id="r"></pre> 

Is that data format you have fixed? 您修复了这种数据格式吗? You should consider doing something more like 你应该考虑做更像的事情

school
    -> info (name, etc.)
    -> [classes]
       -> info
       -> [student_ids]
    -> [students]
       -> info (id)

If you can't change your format. 如果您无法更改格式。 You could do something like what you want with Underscore.js#default . 你可以用Underscore.js#default做你想要的事情。 Assuming line_id=0 is always data[0] : 假设line_id=0始终是data[0]

var keys = ['minage','maxage','time'];
var temp = _.pick(data.shift(),keys);
data.forEach(function(e, i, a) {
    a[i] = _.default(e,temp);
});

It doesn't really reduce your complexity because you're basically looking an array of size N and update properties count M, meaning you'll have a complexity of O(N*M). 它并没有真正降低您的复杂性,因为您基本上看起来是一个大小为N的数组,并且更新属性计数为M,这意味着您将具有O(N * M)的复杂度。 If you want something less complex, don't move/copy the data. 如果您想要不那么复杂的东西,请不要移动/复制数据。 Reuse it in the current form. 以当前形式重复使用它。

Since you say that you are copying the same values from the 0th element, you can store it in a variable(say new_data ) and then iterate through the data array and just add them there. 既然你说你正在从第0个元素复制相同的值,你可以将它存储在一个变量(比如new_data )中,然后遍历data数组并在那里添加它们。
This is as complex as iterating through data and inserting key-val pairs. 这与迭代data和插入key-val对一样复杂。
Something like this - 像这样的东西 -

> new_data = {}
//Getting all the content with header keys in data into new_data
> headers.forEach(function(v){new_data[v] = data[0][v]})

//Storing the new_data
> new_data
Object {time: "4-5", minage: "15", maxage: "35"}

//Adding the new_data into data
> data.forEach(function(d_val){
    for(k_nd in new_data){
        d_val[k_nd] = new_data[k_nd];
    }
  });

//Removing the 0th array element
> data.splice(0, 1)

//Checking it 
> JSON.stringify(data[0])
"{"name":"studentname1","line id":"1","class":"A","time":"4-5","minage":"15","maxage":"35"}"

Using lodash library: 使用lodash库:

 var headers = ["time", "minage", "maxage"]; var data = [{ "name": "schoolname", "line id": "0", "time": "4-5", "minage": "15", "maxage": "35" }, { "name": "studentname1", "line id": "1", "class": "A" }, { "name": "studentname2", "line id": "2", "class": "B" }]; var temp = _.pick(data[0], headers); data.splice(0, 1); for (var i = 0; i < data.length; i++) { _.merge(data[i], temp); } var result = JSON.stringify(data); $('#result').text(result); 
 <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="result"></div> 


EDIT: Found a significant performance booster, faster than all other tested solutions so far: extracting one of the loops and applying via: new Function(...) . 编辑:发现一个重要的性能助推器,比目前为止所有其他测试解决方案更快:提取其中一个循环并应用via: new Function(...) Essentially an eval -like approximation of Object.defineProperties(...) . 基本上是Object.defineProperties(...)Object.defineProperties(...) eval的近似值。 Have added this to the performance tests below: 已将此添加到以下性能测试中:

 function addHeadersNewFunc(arr, headers) { //console.time('addHeadersNewFunc'); var header = arr.shift(), funcBody = ['return item;'], headerPropName, setProps; for(var h = headers.length; h--;) { headerPropName = headers[h]; funcBody.unshift('item["' + headerPropName + '"]="' + header[headerPropName] + '";'); //unshift since loop is reversed and we want props in same add order as other implementations, and we've already added our first line } setProps = new Function('item', funcBody.join('')); //warning, this is a form of 'eval()'... for (var i = arr.length; i--;) { setProps(arr[i]); } //console.timeEnd('addHeadersNewFunc'); return arr; } 

Some interesting results testing a few different approaches. 测试几种不同方法的一些有趣结果。 I've only just whipped up the performance testing code, happy for any recommended improvements. 我只是掀起了性能测试代码,对任何建议的改进感到高兴。 I've also added some additional implementations - a string replacement approach, and a lazy getter. 我还添加了一些额外的实现 - 字符串替换方法和懒惰的getter。

In general it looks like the original loop outperforms most of the other suggestions; 一般来说,原始循环看起来优于大多数其他建议; except for the implementation by @Chris Anderson-MSFT using Underscore's defaults when tested in Chrome, which appeared to actually be faster (didn't fare as well in IE, however). 除了@Chris Anderson-MSFT在Chrome中测试时使用Underscore defaults时的实现,实际上看起来实际上更快(但在IE中并不好)。 Otherwise, the lazies performed consistently well, also. 否则,懒惰也表现得很好。 (* EDIT: as per above, implementation using new Function() eventually found to be fastest; for large objects/iterations, significantly). (* 编辑:如上所述,使用new Function()最终发现最快;对于大型对象/迭代,显着)。


Sample output of the below snippet (Chrome 43): 以下代码段的示例输出(Chrome 43):

 Items: 2000 Output of functions is all consistent: true Testing... addHeadersOrig x 1000: [Avg] 2.3977ms, [Min] 2.3170ms, [Max] 2.8280ms addHeadersDefineProp x 1000: [Avg] 6.3481ms, [Min] 6.1010ms, [Max] 15.1750ms addHeadersStrReplace x 1000: [Avg] 3.0551ms, [Min] 2.6630ms, [Max] 5.9910ms addHeadersUnderscoreDefaults x 1000: [Avg] 1.4344ms, [Min] 1.1800ms, [Max] 9.5100ms addHeadersLazy x 1000: [Avg] 2.4529ms, [Min] 2.3460ms, [Max] 6.0770ms addHeadersLazyMemo x 1000: [Avg] 2.4837ms, [Min] 2.3760ms, [Max] 3.8420ms addHeadersNewFunc x 1000: [Avg] 0.0959ms, [Min] 0.0430ms, [Max] 0.5070ms 

 (function() { "use strict"; var arr = [{ "name": "schoolname", "line id": "0", "time": "4-5", "minage": "15", "maxage": "35" }, { "name": "studentname1", "line id": "1", "class": "A" }, { "name": "studentname2", "line id": "2", "class": "B" }], headers = ["time", "minage", "maxage"]; //add some more... for (var i = 3, iLen = 2000; i < iLen; i++) { arr.push({ name: "studentname" + i, "line id": String(i), "class": "C" }); } function addHeadersOrig(arr, headers) { //console.time('addHeadersOrig'); for (var i = 1; i < arr.length; i++) //iterate over the data leaving the 1st line { for (var j = 0; j < headers.length; j++) //add each header to the data lines { arr[i][headers[j]] = arr[0][headers[j]]; } } arr.splice(0, 1); //console.timeEnd('addHeadersOrig'); return arr; } function addHeadersDefineProp(arr, headers) { //console.time('addHeadersDefineProp'); var header = arr.splice(0, 1)[0], propObj = headers.reduce(function headerReduce(acc, el) { acc[el] = { value: header[el], writable: true, enumerable: true }; return acc; }, {}); for (var i = 0, len = arr.length; i < len; i++) { Object.defineProperties(arr[i], propObj); } //console.timeEnd('addHeadersDefineProp'); return arr; } function addHeadersStrReplace(arr, headers) { //console.time('addHeadersStrReplace'); var header = arr.shift(), propObj = {}; for (var i = 0; i < headers.length; i++) { propObj[headers[i]] = header[headers[i]]; } //stringify the array, replace each '}' with a ',' followed by the the stringified propObj (minus its opening bracket) which brings its own closing bracket to make up for the one we replaced; then parse back to an object arr = JSON.parse(JSON.stringify(arr).replace(/\\}/g, ',' + JSON.stringify(propObj).slice(1))); //console.timeEnd('addHeadersStrReplace'); return arr; } //only runs using lodash, not underscore function addHeadersLodashMerge(arr, headers) { //console.time('addHeadersLodashMerge'); var temp = _.pick(arr.shift(), headers); for (var i = 0; i < arr.length; i++) { _.merge(arr[i], temp); } //console.timeEnd('addHeadersLodashMerge'); return arr; } //runs under both lodash and underscore - faster in underscore AFAICT function addHeadersUnderscoreDefaults(arr, headers) { //console.time('addHeadersUnderscoreDefaults'); var temp = _.pick(arr.shift(), headers); arr.forEach(function(e, i, a) { a[i] = _.defaults(e, temp); }); //console.timeEnd('addHeadersUnderscoreDefaults'); return arr; } function addHeadersNewFunc(arr, headers) { //console.time('addHeadersNewFunc'); var header = arr.shift(), funcBody = ['return item;'], headerPropName, setProps; for(var h = headers.length; h--;) { headerPropName = headers[h]; funcBody.unshift('item["' + headerPropName + '"]="' + header[headerPropName] + '";'); //unshift since loop is reversed and we want props in same add order as other implementations, and we've already added our first line } setProps = new Function('item', funcBody.join('')); //warning, this is a form of 'eval()'... for (var i = arr.length; i--;) { setProps(arr[i]); } //console.timeEnd('addHeadersNewFunc'); return arr; } function addHeadersLazy(arr, headers) { //console.time('addHeadersLazy'); var lazy = new Lazy(arr, headers), result = []; for (var i = 1; i < arr.length; i++) { result.push(lazy.get(i)); } //console.timeEnd('addHeadersLazy'); return result; } function addHeadersLazyMemo(arr, headers) { //console.time('addHeadersLazyMemo'); var lazy = new Lazy(arr, headers, true), result = []; for (var i = 1; i < arr.length; i++) { result.push(lazy.get(i)); } //console.timeEnd('addHeadersLazyMemo'); return result; } function Lazy(arr, headers, useMemo) { var headerValSrc = arr[0], headerLen = headers.length, memo = []; function _get(index) { for (var j = 0; j < headerLen; j++) { arr[index][headers[j]] = headerValSrc[headers[j]]; } return arr[index]; } function _getMemo(index) { if (memo[index]) { return memo[index]; } for (var j = 0; j < headerLen; j++) { arr[index][headers[j]] = headerValSrc[headers[j]]; } return (memo[index] = arr[index]); } return { get: (useMemo ? _getMemo : _get) }; } function clone(data) { return JSON.parse(JSON.stringify(data)); } function perfTest(name, testFunc) { name = name ? name : "Test"; var iterations = 1000, argsSliced = Array.prototype.slice.call(arguments, 2), args = [], t0 = 0, t1, t2, t3, tmin = 1000000, tmax = 0, output; setTimeout(function delayAllowingDocWrite() { for (var i = 0; i < iterations; i++) { args = clone(argsSliced); t1 = performance.now(); testFunc.apply(this, args); t2 = performance.now(); t3 = t2 - t1; tmin = t3 < tmin ? t3 : tmin; tmax = t3 > tmax ? t3 : tmax; t0 += t3; } output = name + " x " + iterations + ": [Avg] " + (t0 / iterations).toFixed(4) + "ms, [Min] " + tmin.toFixed(4) + "ms, [Max] " + tmax.toFixed(4) + "ms"; console.log(output); document.body.innerHTML += (output + "<br />"); }, 10); return testFunc.apply(this, clone(argsSliced)); //return output of function immed, once, for comparing results } document.body.innerHTML += "Items: " + arr.length + "<br />"; console.log("Items: ", arr.length); //* var resultOrig = perfTest("addHeadersOrig", addHeadersOrig, arr, headers), resultDefineProp = perfTest("addHeadersDefineProp", addHeadersDefineProp, arr, headers), resultStrReplace = perfTest("addHeadersStrReplace", addHeadersStrReplace, arr, headers), //resultLodashMerge = perfTest("addHeadersLodashMerge", addHeadersLodashMerge, arr, headers), //re-enable if using lodash.min.js resultUnderscoreDefaults = perfTest("addHeadersUnderscoreDefaults", addHeadersUnderscoreDefaults, arr, headers), resultLazy = perfTest("addHeadersLazy", addHeadersLazy, arr, headers), resultLazyMemo = perfTest("addHeadersLazyMemo", addHeadersLazyMemo, arr, headers), resultNewFunc = perfTest("addHeadersNewFunc", addHeadersNewFunc, arr, headers); //*/ var resultOrigStr = JSON.stringify(resultOrig), outputIsConsistent = "Output of functions is all consistent: " + ( resultOrigStr === JSON.stringify(resultDefineProp) && resultOrigStr === JSON.stringify(resultStrReplace) && //resultOrigStr === JSON.stringify(resultLodashMerge) && resultOrigStr === JSON.stringify(resultUnderscoreDefaults) && resultOrigStr === JSON.stringify(resultLazy) && resultOrigStr === JSON.stringify(resultLazyMemo) && resultOrigStr === JSON.stringify(resultNewFunc) ); document.body.innerHTML += outputIsConsistent + "<br /><em>Testing...</em><br /><br />"; console.log(outputIsConsistent); if (!window.performance || !window.performance.now) { document.body.innerHTML += "Your browser does not seem to support performance.now()..."; } /* var arr1 = clone(arr), arr2 = clone(arr), arr3 = clone(arr), arr4 = clone(arr), arr5 = clone(arr), arr6 = clone(arr); var resultOrig = addHeadersOrig(arr1, headers), resultDefineProp = addHeadersDefineProp(arr2, headers), resultStrReplace = addHeadersStrReplace(arr3, headers), resultLodash = addHeadersLodash(arr4, headers), resultLazy = addHeadersLazy(arr5, headers), resultLazyMemo = addHeadersLazyMemo(arr6, headers); console.log(resultOrig); console.log(resultDefineProp); console.log(resultStrReplace); console.log(resultLodash); console.log(resultLazy); console.log(resultLazyMemo); //*/ })(); 
 body { font-size: 0.8em; font-family: "Arial", sans-serif; } 
 <!--script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js"></script--> <script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> <p>Use a browser that supports performance.now().</p> 


For easier playing around with: Plnkr 为了更容易玩: Plnkr

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

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