Last active
May 13, 2020 08:41
-
-
Save spacecowboy/5749ba82227a5ce410f93c9dd2d46cc4 to your computer and use it in GitHub Desktop.
Calculates the cartesian product of an arbitrary number of lists
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
Calculates the cartesian product of an arbitrary number of lists. | |
Given `[[1, 2, 3], ["a", "b"]]`, it will produce | |
``` | |
[ | |
[1, "a"], | |
[2, "a"], | |
[3, "a"], | |
[1, "b"], | |
[2, "b"], | |
[3, "b"], | |
] | |
``` | |
Useful if you have a parameterized test which needs to test all combinations of all arguments. | |
*/ | |
fun cartesianProduct(args: List<List<Any?>>): List<List<Any?>> { | |
return cartesianProductRec( | |
args = args, | |
indices = List(args.count()) { 0 }, | |
product = mutableListOf() | |
) | |
} | |
tailrec fun cartesianProductRec( | |
args: List<List<Any?>>, | |
indices: List<Int>, | |
product: MutableList<List<Any?>> | |
): List<List<Any?>> { | |
val arguments = mutableListOf<Any?>() | |
val nextIndices = mutableListOf<Int>() | |
// Increase index by this much | |
var carry = 1 | |
for ((index, arg) in indices.zip(args)) { | |
arguments.add(arg[index]) | |
val nextIndex = if (carry == 0) { | |
index | |
} else { | |
if (index + carry > arg.lastIndex) { | |
0.also { | |
carry = index + carry - arg.lastIndex | |
} | |
} else { | |
(index + carry).also { | |
carry = 0 | |
} | |
} | |
} | |
nextIndices.add(nextIndex) | |
} | |
product.add(arguments) | |
return if (carry == 1) { | |
// We're done - no more indices possible to iterate | |
product | |
} else { | |
cartesianProductRec(args, nextIndices, product) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment