Skip to content

Commit e652f01

Browse files
natecook1000Tim Vermeulen
andauthored
Add uniquePermutations as wrapper for nextPermutation (#91)
* Add uniquePermutations as wrapper for nextPermutation * Implement uniquePermutations(ofCount:) variants * Simplify UniquePermutations.Iterator.next() * Add tests for uniquePermutations * Move to a predicate-based uniquePermutations * Add method documentation * Convert to Hashable-based uniquing instead of Comparable * Streamline tests, cover uniqueness * Use optional count to collapse no-count method * Update API documentation * Remove leftover version of nextPermutation() * Remove Hashable requirement from the UniquePermutations type * Update documentation * Apply Tim's great revisions Co-authored-by: Tim Vermeulen <[email protected]> * Add lazy conformance to UniquePermutations Co-authored-by: Tim Vermeulen <[email protected]>
1 parent 9783c1b commit e652f01

File tree

4 files changed

+451
-87
lines changed

4 files changed

+451
-87
lines changed

Guides/Permutations.md

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[[Source](https://github.com/apple/swift-algorithms/blob/main/Sources/Algorithms/Permutations.swift) |
44
[Tests](https://github.com/apple/swift-algorithms/blob/main/Tests/SwiftAlgorithmsTests/PermutationsTests.swift)]
55

6-
A type that computes permutations of a collection’s elements, or of a subset of
6+
Methods that compute permutations of a collection’s elements, or of a subset of
77
those elements.
88

99
The `permutations(ofCount:)` method, when called without the `ofCount`
@@ -60,7 +60,18 @@ for perm in numbers2.permutations() {
6060
// [10, 10, 20]
6161
```
6262

63-
Given a range, the `permutations(ofCount:)` method returns a sequence of all the different permutations of the given sizes of a collection’s elements in increasing order of size.
63+
To generate only unique permutations, use the `uniquePermutations(ofCount:)` method:
64+
65+
```swift
66+
for perm in numbers2.uniquePermutations() {
67+
print(perm)
68+
}
69+
// [20, 10, 10]
70+
// [10, 20, 10]
71+
// [10, 10, 20]
72+
```
73+
74+
Given a range, the methods return a sequence of all the different permutations of the given sizes of a collection’s elements in increasing order of size.
6475

6576
```swift
6677
let numbers = [10, 20, 30]
@@ -87,28 +98,40 @@ for perm in numbers.permutations(ofCount: 0...) {
8798

8899
## Detailed Design
89100

90-
The `permutations(ofCount:)` method is declared as a `Collection` extension,
91-
and returns a `Permutations` type:
101+
The `permutations(ofCount:)` and `uniquePermutations(ofCount:)` methods are declared as `Collection` extensions,
102+
and return `Permutations` and `UniquePermutations` instances, respectively:
92103

93104
```swift
94105
extension Collection {
95106
public func permutations(ofCount k: Int? = nil) -> Permutations<Self>
107+
public func permutations<R>(ofCount kRange: R) -> Permutations<Self>
108+
where R: RangeExpression, R.Bound == Int
109+
}
110+
111+
extension Collection where Element: Hashable {
112+
public func uniquePermutations(ofCount k: Int? = nil) -> UniquePermutations<Self>
113+
public func uniquePermutations<R>(ofCount kRange: R) -> UniquePermutations<Self>
114+
where R: RangeExpression, R.Bound == Int
96115
}
97116
```
98117

99-
Since the `Permutations` type needs to store an array of the collection’s
100-
indices and mutate the array to generate each permutation, `Permutations` only
101-
has `Sequence` conformance. Adding `Collection` conformance would require
118+
Since both result types need to store an array of the collection’s
119+
indices and mutate the array to generate each permutation, they only
120+
have `Sequence` conformance. Adding `Collection` conformance would require
102121
storing the array in the index type, which would in turn lead to copying the
103-
array at every index advancement. `Combinations` does conform to
104-
`LazySequenceProtocol` when the base type conforms.
122+
array at every index advancement. The `Permutations` type
123+
conforms to `LazySequenceProtocol` when its base type conforms.
105124

106125
### Complexity
107126

108127
Calling `permutations()` is an O(1) operation. Creating the iterator for a
109128
`Permutations` instance and each call to `Permutations.Iterator.next()` is an
110129
O(_n_) operation.
111130

131+
Calling `uniquePermutations()` is an O(_n_) operation, because it preprocesses the
132+
collection to find duplicate elements. Creating the iterator for and each call to
133+
`next()` is also an O(_n_) operation.
134+
112135
### Naming
113136

114137
See the ["Naming" section for `combinations(ofCount:)`](Combinations.md#naming) for detail.
@@ -117,9 +140,8 @@ See the ["Naming" section for `combinations(ofCount:)`](Combinations.md#naming)
117140

118141
**C++:** The `<algorithm>` library defines a `next_permutation` function that
119142
advances an array of comparable values through their lexicographic orderings.
120-
This function is tricky to use and understand, so while it’s included in
121-
`swift-algorithms` as an implementation detail of the `Permutations` type, it
122-
isn’t public.
143+
This function is very similar to the `uniquePermutations(ofCount:)` method.
123144

124145
**Rust/Ruby/Python:** Rust, Ruby, and Python all define functions with
125-
essentially the same semantics as the method described here.
146+
essentially the same semantics as the `permutations(ofCount:)` method
147+
described here.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Read more about the package, and the intent behind it, in the [announcement on s
1010

1111
- [`combinations(ofCount:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Combinations.md): Combinations of particular sizes of the elements in a collection.
1212
- [`permutations(ofCount:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Permutations.md): Permutations of a particular size of the elements in a collection, or of the full collection.
13+
- [`uniquePermutations(ofCount:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Permutations.md): Permutations of a collection's elements, skipping any duplicate permutations.
1314

1415
#### Mutating algorithms
1516

0 commit comments

Comments
 (0)