我试图找到最简单的方法来找到数组中每个数字的因子而不使用循环。我有一个ES6代码片段,我可以在.map中使用以避免我认为的循环,但我不知道它在第二行中做了什么。
我已经查看了MDN上的.filter和.from方法,所以我们只是通过调用Array()从一个可迭代的复制数组实例,似乎是空的,但是后来我无法用英语描述它在那之后,这让我感到不安。
let evens = [2,4,6,80,24,36];
这是我试图用英语解构/解释的ES6片段
const factor = number => Array
.from(Array(number), (_, i) => i)
.filter(i => number % i === 0)
所以我把它放到这个.map中就像这样
const factors = evens.map((number => {
return factors(number)
}))
console.log(factors)
我得到了一系列因子数组,如下所示
[ [ 1 ],
[ 1, 2 ],
[ 1, 2, 3 ],
[ 1, 2, 4, 5, 8, 10, 16, 20, 40 ],
[ 1, 2, 3, 4, 6, 8, 12 ],
[ 1, 2, 3, 4, 6, 9, 12, 18 ] ]
所以......它有效,但第二行发生了什么?我喜欢它简洁,但是当我试图将它逆向工程化为非ES6时,我不知道了。
先谢谢你,先进的ES6人。
这里要解开很多东西。
首先,“不使用循环”。你能解释一下这个要求的原因吗?并不是说我没有同情心,因为我通常会避免显式循环,但你应该能够解释为什么要这样做。处理有序集合有两种根本不同的方法:迭代循环和递归。如果你不使用递归代码,可能会隐藏某个循环。它可能被埋没在map
,filter
等中,这通常是一种改进,但那个循环仍然存在。
其次,这个片段的布局相当误导:
const factor = number => Array
.from(Array(number), (_, i) => i)
.filter(i => number % i === 0)
通常当多行开始.methodName(...)
时,这些方法中的每一个都对前一行提供的数据进行操作。但from
这里只是Array
的静态方法;像这样将它们分开是令人困惑的。这些中的任何一个都会更好,就像许多其他布局一样:
const factor = number =>
Array.from(Array(number), (_, i) => i)
.filter(i => number % i === 0)
const factor = number => Array.from(
Array(number),
(_, i) => i
).filter(i => number % i === 0)
第三,正如评论和另一个答案所指出的那样,Array.from
接受一个迭代和一个映射函数并返回一个数组,而Array(number)
将给你一个没有值的数组,但它将其长度报告为number
,因此将作为一个合适的可迭代。有人可能会写出许多等效方法,例如:
Array.from({length: number}, (_, i) => i)
[...Array(number)].map((_, i) => i)
第四,你提到这个:
const factors = evens.map((number => {
return factor(number)
}))
(错字修正)
虽然这没有什么不妥,但你可能想要认识到这可以写得更清晰
const factors = evens.map(factor)
最后,该分解代码缺少主要的性能调整。你可以测试每个可能的值到n
,当你真的可以成对找到因子时,只测试sqrt(n)
。这是一个主要的区别。没有已知的有效保理技术,这可能是一件好事,因为现代加密取决于这是一个难题。但你很可能不想让它变得更糟。
Array(number)
创建一个空数组,长度为number
。现在因为它是完全空的,所以长度还没有真正有用...如果你在它上面调用Array.from
,它会迭代所有索引(直到number
)然后调用传递的回调并构建一个带有返回值的新数组。 (_, i) => i
获取前一个值的索引(始终为undefined
)并将其作为值返回。因此,您会得到以下结果:
number | Array.from
0 | []
1 | [0]
2 | [0, 1]
5 | [0, 1, 2, 3, 4]
如你所见,这会产生从0到number
的所有数字。现在你只需要过滤掉那些均匀分割number
的东西,这可以通过再次检查模运算的结果来轻松完成:
1 % 2 -> 1
2 % 2 -> 0
3 % 2 -> 1
4 % 2 -> 0
我认为更有效的方法是使用发电机。
奖金是我认为代码更容易理解。
let evens = [2,4,6,80,24,36];
function* factor(n) {
for (let l = 1; l < n; l += 1) {
if (n % l === 0) yield l;
}
}
const factors = evens.map((number => {
return Array.from(factor(number)).join(", ");
}));
console.log(factors);