2

I'm attempting to port the function found in this answer from Python to ES6 (minus the sorting, which I don't need), but can't reproduce the same output.

Instead of returning only the partitions of a given length, as in the Python version, it is currently returning all of the partitions up to and including that length.

In the below example, the desired output is arrays of length 3 to be returned only.

Have I misunderstood some aspect of the generator function?

const kPartitions = (seq, k) => {
  const n = seq.length
  var groups = []
  function* generatePartitions(i) {
    if (i >= n) {
      yield groups.map(group => [...group])
    }
    else {
      if (n - 1 > k - groups.length) {
        for (let group of groups) {
          group.push(seq[i])
          yield* generatePartitions(i + 1)
          group.pop()
        }
      }
      if (groups.length < k) {
        groups.push([seq[i]])
        yield* generatePartitions(i + 1)
        groups.pop()
      }
    }
  }
  return generatePartitions(0)
}

for (var partitions of kPartitions(['A', 'B', 'C', 'D'], 3)) {
  console.log(partitions)
}

Also as a bin.

1 Answers1

1

No, there is just an error in your conversion from Python to ES6.

On the line where you have if (n - 1 > k - groups.length), the 1 should be an i instead (just a transcription error).

So the correct version of that line would be:

if (n - i > k - groups.length)

Once that's changed it gives the expected output:

[["A", "B"], ["C"], ["D"]]
[["A", "C"], ["B"], ["D"]]
[["A"], ["B", "C"], ["D"]]
[["A", "D"], ["B"], ["C"]]
[["A"], ["B", "D"], ["C"]]
[["A"], ["B"], ["C", "D"]]

Now I'm interested to dig in and see how it actually works ;)


Here is the full code with that change made:

const kPartitions = (seq, k) => {
  const n = seq.length
  var groups = []
  function* generatePartitions(i) {
    if (i >= n) {
      yield groups.map(group => [...group])
    }
    else {
      if (n - i > k - groups.length) {
        for (let group of groups) {
          group.push(seq[i])
          yield* generatePartitions(i + 1)
          group.pop()
        }
      }
      if (groups.length < k) {
        groups.push([seq[i]])
        yield* generatePartitions(i + 1)
        groups.pop()
      }
    }
  }
  return generatePartitions(0)
}

for (var partitions of kPartitions(['A', 'B', 'C', 'D'], 3)) {
  console.log(partitions)
}
Sly_cardinal
  • 12,270
  • 5
  • 49
  • 50
  • Argh, many thanks. The algorithm is well-explained in the linked post. –  Jan 26 '18 at 08:15