Add next_permutation and prev_permutation onto MutableTotalOrdVector<T>. #13761
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Okay, so first out, I'm no sure if this is okay as a pull request (without prior discussion or an RFC). However, considering that
and the fact that the community is supposed to be friendly to strangers and beginners, I figured not too much could go wrong; worst case, the pull request is not accepted, right? :-)
I looked at the existing RFCs, but all of them felt bigger in scope than simply adding a few function (causing no backwards incompatibility).
Anyway. This adds two methods to mutable vectors (
MutableTotalOrdVector<T>
): next_permutation() and prev_permutation().They mutate the vector to the next/previous lexicographic permutation, in place.
The existing permutation functionality, ImmutableCloneableVector::permutations(), uses iterators and clones the entire vector each iteration, resulting in bad performance. For even a 10-element vector, that causes 10! = 3628800 calls to clone(), on the entire 10-element vector.
It also uses a swapping algorithm which does not generate lexicographic permutations; if you want lexicographical permutations, as far as I can tell, Rust currently cannot provide that.
So does Rust need this? I don't know. I wanted to use it, and realized it didn't exist, so I created it. Others may disagree about the necessity, of course.
Sample benchmarks:
51x faster per single iteration (one permutation per benchmark iteration), 35x faster to loop through all 5040 permutations of range(0,7) per benchmark iteration.
One possible (style-ish) issue with this code is the return types: they return
true
if successful, andfalse
if the vector was already at the first/last permutation. This makes looping rather easy, but I'm not sure if it's considered "pretty", so to speak. However, since iterators are much too expensive, at least if returning a cloned vector each iteration is the only way to make them work, I found no better way to solve this, and at least IMHO it looks fine.Also, I'm not sure if the comments inside the actual functions is considered excessive or not, but that is of course easily changed, if that would be the case.
BTW, I have ran more tests than actually submitted; the full suite would be excessive to submit, but can be viewed here (please excuse the messy code).