JavaScript生成器函数在尝试复制Python时超时';s itertools.组合
在这里有几个答案的帮助下,我已经能够开始学习生成器并开发以下功能:JavaScript生成器函数在尝试复制Python时超时';s itertools.组合,javascript,python,ecmascript-6,combinations,permutation,Javascript,Python,Ecmascript 6,Combinations,Permutation,在这里有几个答案的帮助下,我已经能够开始学习生成器并开发以下功能: function* icombinations(arr, k) { function* getCombinations(newArr, shift) { if (newArr.length === k) { yield newArr; } for (let i = shift; i < arr.length; i++) { yield* getCombinations
function* icombinations(arr, k) {
function* getCombinations(newArr, shift) {
if (newArr.length === k) {
yield newArr;
}
for (let i = shift; i < arr.length; i++) {
yield* getCombinations([...newArr, arr[i]], i + 1);
}
}
yield* getCombinations([], 0);
return [];
}
函数*i组合(arr,k){
函数*getCombinations(newArr、shift){
if(newArr.length==k){
产量新增;
}
for(设i=shift;i
以下是repl.it的链接:
我可能还没有完全理解这个概念,因为上面的函数会超时很长时间,因为我试图先生成所有可能的组合,然后生成每个组合。你知道我如何重构函数,这样我就不会先生成所有的组合了吗
以下是我试图解决的挑战的描述:
编写一个名为icombinations
的函数,该函数应该是一个生成器函数,其行为类似于
Python的itertools.compositions。您将获得一个唯一的数组arr
项目和整数k
您应该在长度arr
中生成每个元素的唯一组合
k
在没有可能的唯一性之前不进行替换
左侧组合,此时应终止生成器
功能。在某些情况下,将使用next()
调用生成器
它将被调用,直到完成
此外,以相同的格式返回组合也很重要
按原始阵列的顺序排列arr
。(见下面的例子)
例如:
给定一个唯一元素数组示例\u arr
和一个整数
示例k
:
其中example_arr=['a','b','c','d']
和example_k=2
调用迭代器的next()
方法应返回['a','b']
如果我们再次调用next()
,我们应该得到['a','c']
等等
在
因此,如果我们得到生成器产生的所有值,我们将
以下是:
['a','b']['a','c']['a','d']['b','c']['b','d'][
“c”,“d']
请再次注意上面的顺序,因为您需要
在您的解决方案中复制它
还有一些事情需要考虑:
如果您的解决方案超时,可能是因为您试图
首先生成所有可能的组合,然后生成每个组合。
这违背了发电机的观点。一些输入值将被删除
大的
arr
中的值始终是唯一的,但它们可能是不同类型的
(即字符串、整数和其他对象)
您无法生成组合的唯一情况
是指arr
为空或长度小于k
的值。在里面
在这些情况下,您应该返回一个空数组
您可能能够在代码审查方面获得更好的建议,但您可以尝试的一个改进是删减一些“死胡同”递归路径。因为您知道每个结果必须是length
k
,所以只有当源数组中剩下足够的元素来实际完成k子集时,才应该递归
function* icombinations(arr, k) {
function* getCombinations(newArr, shift) {
if (newArr.length === k) {
yield newArr;
}
// if what's available is >= what's needed
else if (arr.length - shift >= k - newArr.length) {
for (let i = shift; i < arr.length; i++) {
yield* getCombinations([...newArr, arr[i]], i + 1);
}
}
}
yield* getCombinations([], 0);
return [];
}
函数*i组合(arr,k){
函数*getCombinations(newArr、shift){
if(newArr.length==k){
产量新增;
}
//如果可用的>=需要的
else if(arr.length-shift>=k-newArr.length){
for(设i=shift;i
但是如果没有您的测试用例或对arr.length
和k
的限制,我们就无法知道这是否足够好。您提到,arr.length
可以是50,这意味着当k
为25时,最多有126410606437752个子集。无论算法有多高效,都无法在合理的时间内完成。即使k
为5(或相当于45),您也会看到2118760个组合
您可以尝试的另一件事是在内部函数外部预先分配子集数组(newArr
),然后在每次递归调用之前就地更新数组。这避免了每次要向其追加值时都需要复制newArr
,但在基本情况下仍需要生成newArr
的副本。然而,与分支修剪相比,这更像是一种微观优化。首先自己尝试修剪,看看每个更改能带来多少改进
最后,您还可以切换到迭代实现,看看它是否有效。不要先生成所有的实现;这就是拥有发电机的意义所在。您的描述明确地说明了这一点(首先要考虑的事情)。谢谢Scott,我已经读了好几遍了,不知怎的,我不知道如何修改函数。我想唯一的问题是
返回[]
。据我所知,这不属于那里。@ScottSauyet我需要添加return[]
语句,因为质询底部的要求。该函数提供所有必需的结果,唯一的问题是它对长数组超时。@PiotrBerebecki在您仅调用icombinations()
或迭代结果时超时吗?还有,这些“长数组”有多长?