了解此类递归情况的典型方法是假设它适用于较小的情况,然后查看较大的情况如何进行。
所以我们假设combinations(['b', 'c', 'd'], 1) 产生值['b'],然后是['c'],然后是'[d]',同样combinations(['c', 'd'], 1) 产生['c'],然后是['d'],而combinations(['d'], 1) 只产生@ 987654329@,最后combinations([], 1) 什么也没有产生。
现在让我们来看看combinations(['a', 'b', 'c', 'd'], 2):
我们将i从0迭代到3:
-
当i = 0, elements[i] = 'a' 我们看到length 是2,所以不是== 1。我们计算remaining = combinations(['b', 'c', 'd'], 1),根据我们的假设,得到['b'],然后是['c'],然后是['d']。所以对于每一个我们产生[elements[i], ...(the yielded value)],这意味着我们产生['a', 'b'],然后是['a', 'c'],然后是['a', 'd']
-
当i = 1, elements[i] = 'b' 时,我们看到length 是2,所以不是== 1。我们计算remaining = combinations(['c', 'd'], 1),根据我们的假设产生['c'],然后是['d']。所以对于其中的每一个,我们产生[elements[i], ...(the yielded value)],这意味着我们产生['b', 'c'],然后是['b', 'd']。
-
当i = 2, elements[i] = 'c' 时,我们看到length 是2,所以不是== 1。我们计算remaining = combinations(['d'], 1),根据我们的假设得出['d']。因此,对于(仅)其中一个,我们产生 [elements[i], ...(the yielded value)],这意味着我们产生 ['c', 'd']。
-
当i = 3, elements[i] = 'd' 我们看到length 是2,所以不是== 1。我们计算 `remaining = combination([], 1),根据我们的假设不会产生任何结果,所以在这种情况下我们也不会产生任何结果。
因此,总的来说,我们产生了以下值:['a', 'b']、['a', 'c']、['a', 'd']、['b', 'c']、['b', 'd'] 和 ['c', 'd'],这正是来自 @ 的两个元素的组合集987654387@.
当length = 1 时,您当然还需要检查基本情况,但这应该很容易做到。
非生成器方法
有时,生成器方法会使代码更加简洁易懂。不过,这并不是真正的时代之一。
基本上,生成器允许您不必进行复杂的结果收集,而是可以随时yield 它们。如果您可以轻松地收集结果,非生成器代码通常更简单。这是不使用生成器的相同算法:
const combinations = (elements, length) =>
elements .flatMap ((el, i) =>
length == 1
? [el]
: combinations (elements .slice (i + 1), length - 1)
.map (combo => [el, ...combo])
)
console .log (combinations (['a', 'b', 'c', 'd'], 2))
.as-console-wrapper {max-height: 100% !important; top: 0}
我当然觉得这更容易理解。