高效地将 JavaScript 键和值数组转换为对象
Posted
技术标签:
【中文标题】高效地将 JavaScript 键和值数组转换为对象【英文标题】:Efficiently converting JavaScript key and value arrays to object 【发布时间】:2021-03-29 10:08:20 【问题描述】:我需要将两个 javascript 数组转换为对象列表。一个输入数组表示输出对象的键,另一个包含它的值(以及一些其他信息,与此问题无关)。
示例数据:
let theKeys = ['firstName', 'lastName', 'city'];
let theValues = [data: [['John', 'Smith', 'New York'],
['Mike', 'Doe', 'Chicago'],
...
],
otherStuff: ...
];
上述所需的输出:
output = [
firstName: 'John',
lastName: 'Smith',
city: 'New York'
,
firstName: 'Mike',
lastName: 'Doe',
city: 'Chicago',
,
...
]
(这只是一个示例,我的实际数据来自 REST 响应,内容和长度可能会有所不同。我正在使用显示表格数据的 Vue 应用程序。)
下面我现有的代码适用于少量数据,但会导致所有浏览器在处理大量数据时崩溃或挂起。
return this.theValues.flatMap(results =>
let jsonified = [];
for (let v = 0; v < results.theValues.length; v++)
let singleJson = ;
for (let k = 0; k < this.theKeys.length; k++)
let key = this.theKeys[k];
singleJson[key] = results.data[v][k];
jsonified.push(singleJson);
return jsonified;
);
只有几千个结果,这需要几分钟才能运行。我怎样才能让它更快?是否有一些我遗漏的操作可以让我避免嵌套的 for 循环?
【问题讨论】:
this.theValue
的大小是多少,它也是vue中的计算属性吗?
情况不同。如果是 7 岁或 18 岁,一切都很好。如果是 20,429,我就有问题了。它不是计算出来的,它是从远程服务器返回的数据。
在 flatMap 之前包含 console.time('test')
,在返回之前包含 console.timeEnd('test')
,以查看经过的时间。
我将其范围缩小到对theValues
的调用,这实际上是我正在使用的组件的一个道具。我将其替换为Math.random()
,一切都快如闪电。我认为现在是时候提出一个新问题了,更关注 Vue。
@WashingtonGuedes 仅供参考,以防您仍然感兴趣,我最终确实提出了后续问题:***.com/questions/65569982/…
【参考方案1】:
您可以放弃flatMap
,这应该可以节省一些性能,只需使用普通循环执行所有操作:
const result = []
for (const v of theValues)
for (const entry of v.data)
const obj =
for (let i = 0; i < entry.length; i++)
obj[theKeys[i]] = entry[i]
result.push(obj)
编辑:微优化
const result = []
const keysLength = theKeys.length
for (let i = theValues.length - 1; i >= 0; i--)
const data = theValues[i].data
for (let j = data.length - 1; j >= 0; j--)
const entry = data[j]
const obj =
for (let k = keysLength - 1; k >= 0; k--)
obj[theKeys[k]] = entry[k]
result.push(obj)
【讨论】:
【参考方案2】:如果您对属性进行硬编码而不是查看theKeys
,则可以摆脱内部循环,但我怀疑您是否想要这样做。您唯一不需要的是flatMap
。无论如何,大多数通用数组方法的速度并不为人所知(例如,forEach
通常比普通的 for
循环慢)。
FWIW,这似乎表现不错:
let result = [];
for (let i = 0; i < theValues[0].data.length; i++)
let resultObj = ;
for (let j = 0; j < theKeys.length; j++)
resultObj[theKeys[j]] = theValues[0].data[i][j];
result.push(resultObj);
我用 11k 个项目对其进行了测试,它在 Chrome 中运行了大约 5 毫秒。对于 90k 个项目,它仍然只需要大约 30 毫秒。
【讨论】:
此代码在我的应用程序中产生正确的结果,但在 29851 行上运行需要 255388 毫秒。发生了一些奇怪的事情。【参考方案3】:最简单的方法可能是将.map
值转换为键值元组并在其上调用Object.fromEntries
:
const theKeys = ['firstName', 'lastName', 'city'];
const theValues = [
data: [
['John', 'Smith', 'New York'],
['Mike', 'Doe', 'Chicago']
]
];
console.log(
theValues[0].data.map(e =>
Object.fromEntries(e.map((e,i) => [theKeys[i], e]))
)
)
【讨论】:
以上是关于高效地将 JavaScript 键和值数组转换为对象的主要内容,如果未能解决你的问题,请参考以下文章