递归函数有效,生成版本错误
recursive function works, generative version is wrong
这个递归函数可以很好地从数组中获取值的组合:
function combinations(set, k) {
if (k > set.length || k <= 0) return []
if (k === set.length) return [set]
if (k === 1) return set.map(x => [x])
return set.reduce((p, c, i) => {
combinations(set.slice(i + 1), k - 1).forEach(tailArray =>
p.push([c].concat(tailArray)),
)
return p
}, [])
}
我试图将其转换为生成版本:
function* combinations(set, k) {
if (k > set.length || k <= 0) yield []
if (k === set.length) yield set
if (k === 1) yield* set.map(x => [x])
for (let i in set) {
for (const next of combinations(set.slice(+i + 1), k - 1)) {
yield [set[i]].concat(next)
}
}
return
}
但是这个 returns 的结果比它应该的多得多,而且它们的长度也不完全正确
function timeFn(fn){
const pre = performance.now()
const r = fn()
const post = performance.now()
console.log('time', (post - pre)/1000 , 's')
return r
}
timeFn(()=> [...combinations([...Array(4)].map((_,i)=>i+1), 3)])
VM2045:5 time 0.00009999999403953553 s
(20) [Array(3), Array(3), Array(3), Array(4), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(2), Array(3), Array(3), Array(3), Array(3), Array(3), Array(2), Array(1), Array(2), Array(1)]
遗憾的是,这不仅仅是为了...在:
function* combinations(set, k) {
if (k > set.length || k <= 0) yield []
if (k === set.length) yield set
if (k === 1) yield* set.map(x => [x])
for (let i=0,lim=set.length; i<lim; i++) {
for (const next of combinations(set.slice(i + 1), k - 1)) {
yield [set[i]].concat(next)
}
}
return
}
undefined
timeFn(()=> [...combinations([...Array(4)].map((_,i)=>i+1), 3)])
VM2045:5 time 0.00020000000298023223 s
(20) [Array(3), Array(3), Array(3), Array(4), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(2), Array(3), Array(3), Array(3), Array(3), Array(3), Array(2), Array(1), Array(2), Array(1)]
您没有正确地将基本案例转换为生成器版本:
if (k > set.length || k <= 0) return []
if (k === set.length) return [set]
if (k === 1) return set.map(x => [x])
请注意这些 return
,当您的生成器函数继续运行时,发出 所有 个。
function* combinations(set, k) {
if (k > set.length || k <= 0) {
// notice this yields nothing
return
}
if (k === set.length) {
yield set
return
}
if (k === 1) {
yield* set.map(x => [x])
return
}
for (let i=0; i<set.length; i++) {
for (const next of combinations(set.slice(i + 1), k - 1)) {
yield [set[i]].concat(next)
}
}
}
顺便说一句,k === set.length
和 k === 1
不是基本情况,而是(不必要的)优化,并且您的函数对于 k === 0
无法正常工作 - 应该生成一个空数组。更好:
function* combinations(set, k) {
if (k >= 0 && k <= set.length) {
if (k == 0) {
yield [];
} else {
for (const [i, v] of set.entries())
for (const next of combinations(set.slice(i + 1), k - 1)) {
yield [v, ...next];
}
}
}
}
}
这个递归函数可以很好地从数组中获取值的组合:
function combinations(set, k) {
if (k > set.length || k <= 0) return []
if (k === set.length) return [set]
if (k === 1) return set.map(x => [x])
return set.reduce((p, c, i) => {
combinations(set.slice(i + 1), k - 1).forEach(tailArray =>
p.push([c].concat(tailArray)),
)
return p
}, [])
}
我试图将其转换为生成版本:
function* combinations(set, k) {
if (k > set.length || k <= 0) yield []
if (k === set.length) yield set
if (k === 1) yield* set.map(x => [x])
for (let i in set) {
for (const next of combinations(set.slice(+i + 1), k - 1)) {
yield [set[i]].concat(next)
}
}
return
}
但是这个 returns 的结果比它应该的多得多,而且它们的长度也不完全正确
function timeFn(fn){
const pre = performance.now()
const r = fn()
const post = performance.now()
console.log('time', (post - pre)/1000 , 's')
return r
}
timeFn(()=> [...combinations([...Array(4)].map((_,i)=>i+1), 3)])
VM2045:5 time 0.00009999999403953553 s
(20) [Array(3), Array(3), Array(3), Array(4), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(2), Array(3), Array(3), Array(3), Array(3), Array(3), Array(2), Array(1), Array(2), Array(1)]
遗憾的是,这不仅仅是为了...在:
function* combinations(set, k) {
if (k > set.length || k <= 0) yield []
if (k === set.length) yield set
if (k === 1) yield* set.map(x => [x])
for (let i=0,lim=set.length; i<lim; i++) {
for (const next of combinations(set.slice(i + 1), k - 1)) {
yield [set[i]].concat(next)
}
}
return
}
undefined
timeFn(()=> [...combinations([...Array(4)].map((_,i)=>i+1), 3)])
VM2045:5 time 0.00020000000298023223 s
(20) [Array(3), Array(3), Array(3), Array(4), Array(3), Array(3), Array(3), Array(3), Array(3), Array(3), Array(2), Array(3), Array(3), Array(3), Array(3), Array(3), Array(2), Array(1), Array(2), Array(1)]
您没有正确地将基本案例转换为生成器版本:
if (k > set.length || k <= 0) return []
if (k === set.length) return [set]
if (k === 1) return set.map(x => [x])
请注意这些 return
,当您的生成器函数继续运行时,发出 所有 个。
function* combinations(set, k) {
if (k > set.length || k <= 0) {
// notice this yields nothing
return
}
if (k === set.length) {
yield set
return
}
if (k === 1) {
yield* set.map(x => [x])
return
}
for (let i=0; i<set.length; i++) {
for (const next of combinations(set.slice(i + 1), k - 1)) {
yield [set[i]].concat(next)
}
}
}
顺便说一句,k === set.length
和 k === 1
不是基本情况,而是(不必要的)优化,并且您的函数对于 k === 0
无法正常工作 - 应该生成一个空数组。更好:
function* combinations(set, k) {
if (k >= 0 && k <= set.length) {
if (k == 0) {
yield [];
} else {
for (const [i, v] of set.entries())
for (const next of combinations(set.slice(i + 1), k - 1)) {
yield [v, ...next];
}
}
}
}
}