我昨天写了一小段代码,它使用两个for循环来比较两个数组中的对象(尽管数组是相同的)。
var result = []
for (var i = 0; i < res.length; i++) {
var tempObj = {}
tempObj.baseName = res[i].name
tempObj.cnt = res[i].cnt
tempObj.matches = []
for (var j = 0; j < compareArr.length; j++) {
if(natural.LevenshteinDistance(res[i].name, compareArr[j].name) === options.distance) {
tempObj.matches.push(compareArr[j])
}
}
if (tempObj.matches.length > 0) {
result.push(tempObj)
}
}
然而,在过去的几个月里,我一直在进行函数式编程,并决定使用更具功能性的方法重写代码块,最终得到了这个:
var result = res.
map(function(baseItem) {
baseItem.matches = compareArr.
reduce(function(acc, compItem) {
if(natural.LevenshteinDistance(baseItem.name, compItem.name) === options.distance) {
acc.push(compItem)
}
return acc
}, [])
return baseItem
}).
filter(function(item) {
return item.matches.length > 0
})
我的路线觉得响应有点慢,然而,迭代的数据是数据库查询的结果,可能包含数以万计的项目,我想确保我不会受伤服务器的性能无缘无故。所以,我将函数插入到jsperf中,the results令人难过。 for循环以大约2,600 ops / sec运行,而第二个块以大约500 ops / sec运行。 :(
问题是,我的第二块写得不好,可以改进并提速吗?如果没有,这是正常的吗?我看到越来越多的人推动功能风格javascript **。
我是否以风格的名义伤害了表演?我是否应该喜欢学习函数式语言并将其从我的javascript中删除?
** [引用需要amiright?]
http://jhusain.github.io/learnrx/
https://github.com/timoxley/functional-javascript-workshop
https://medium.com/javascript-scene/the-two-pillars-of-javascript-ee6f3281e7f3
John Resig似乎是一个粉丝 - &gt; http://ejohn.org/blog/partial-functions-in-javascript/
http://shop.oreilly.com/product/0636920028857.do
我发现这篇文章非常快速地从非常具体到非常一般,我会编辑范围并在建议时发表新帖。
编辑:为该组添加了lodash和下划线的测试。 Lodash以每秒870次的速度排在第二位,并以每秒475次的速度下调。测试here。
我找到了fast.js与for循环和js本机函数here的基准测试,它同样被一个简单的for循环所震撼。
答案 0 :(得分:0)
数组方法本身比for循环慢,因为1)他们必须在每次迭代时重新构建函数作用域,并且2)其中一些(.map
,.reduce
)必须重建副本数组(所以更多的内存,更多的GarbageCollection和通常更多的操作)。因此,如果您关注速度,请保持尽可能低的速度。
特别是对于您的算法,您可以采取一些措施来改善运行时。您最昂贵的操作是LevenshteinDistance
,因此进行了优化,可以显着提高速度。
你能做的最简单的事情是对字符串进行长度检查并提前返回:你知道如果2个字符串的长度相差超过options.distance
,那么它们的Levenshtein距离至少会更大那么,你可以很容易地早日回归:
for (var j = 0; j < compareArr.length; j++) {
// This check was added
if (Math.abs(res[i].name.length - compareArr[j].name.length) > options.distance) {
continue;
}
if(natural.LevenshteinDistance(res[i].name, compareArr[j].name) === options.distance) {
tempObj.matches.push(compareArr[j])
}
}
该方法本身也有一些改进,在另一个stackoverflow帖子中有更好的解释:https://stackoverflow.com/a/3183199/574576