我有这种格式的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"
}
]
我想做什么
从一组指定的标题中,从"line id" : "0"
获取并将其设置为其他项目。
例如:
headers = ["time", "minage", "maxage"]
我从"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"
}
]
然后使用"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"
}
]
据说第一个元素是"line id" : "0"
。
我尝试过的事情:
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);
一切正常并且符合预期。有没有办法减少时间复杂度并提高效率。
现在的时间复杂度为O(n * m)。
有没有办法将这些少数对象添加到所有元素中?由于要为所有条目添加的键值对保持不变。
答案 0 :(得分:9)
您可以使用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>
答案 1 :(得分:7)
您修复的数据格式是什么?你应该考虑做更像
的事情school
-> info (name, etc.)
-> [classes]
-> info
-> [student_ids]
-> [students]
-> info (id)
如果您无法更改格式。您可以使用Underscore.js#default执行类似的操作。假设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);
});
它并没有真正降低您的复杂性,因为您基本上正在查找大小为N的数组并且更新属性计数M,这意味着您将具有O(N * M)的复杂度。如果您想要不那么复杂的东西,请不要移动/复制数据。以当前形式重复使用。
答案 2 :(得分:3)
由于您说您正在从第0个元素复制相同的值,因此您可以将其存储在变量(例如new_data
)中,然后遍历data
数组并将其添加到那里。
这与迭代data
并插入key-val对一样复杂
像这样的东西 -
> 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"}"
答案 3 :(得分:3)
使用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>
答案 4 :(得分:3)
<小时/> 修改强> 找到 重要 性能助推器,比目前为止所有其他测试解决方案更快:提取其中一个循环并应用via:
new Function(...)
。基本上是eval
- 类似Object.defineProperties(...)
的近似值。已将此添加到以下性能测试中:
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;
}
测试几种不同方法的一些有趣结果。我只是掀起了性能测试代码,对任何建议的改进感到高兴。我还添加了一些额外的实现 - 字符串替换方法和懒惰的getter。
一般来说,原始循环看起来优于大多数其他建议;除了@Chris Anderson-MSFT在Chrome中测试时使用Underscore defaults
的实施情况,实际上看起来实际上更快(但在IE中并没有这样做)。否则,懒惰也表现得很好。 (* 编辑:,如上所述,使用new Function()
的实现最终发现最快;对于大型对象/迭代,显着)。
以下代码段(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);
//*/
})();
&#13;
body {
font-size: 0.8em;
font-family: "Arial", sans-serif;
}
&#13;
<!--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>
&#13;
为了更轻松地玩游戏: Plnkr