Skip to content

Instantly share code, notes, and snippets.

@dfrib

dfrib/tmp.swift Secret

Last active March 29, 2017 17:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dfrib/47a5ee4f393b5c55f3d9a0491f68f3e2 to your computer and use it in GitHub Desktop.
Save dfrib/47a5ee4f393b5c55f3d9a0491f68f3e2 to your computer and use it in GitHub Desktop.
Temp
// from MartinR:s
// http://codereview.stackexchange.com/questions/158798/on-knuths-algorithm-l-to-generate-permutations-in-lexicographic-order
extension Array where Element: Comparable {
// dfri> just changed the return type, and false/true return values to nil/self, respectively
mutating func permute() -> Array? {
// Nothing to do for empty or single-element arrays:
if count <= 1 {
return nil
}
// L2: Find last j such that self[j] <= self[j+1]. Terminate if no such j
// exists.
var j = count - 2
while j >= 0 && self[j] > self[j+1] {
j -= 1
}
if j == -1 {
return nil
}
// L3: Find last l such that self[j] <= self[l], then exchange elements j and l:
var l = count - 1
while self[j] > self[l] {
l -= 1
}
swap(&self[j], &self[l])
// L4: Reverse elements j+1 ... count-1:
var lo = j + 1
var hi = count - 1
while lo < hi {
swap(&self[lo], &self[hi])
lo += 1
hi -= 1
}
return self
}
}
// a downside: explicit 'nil' check / worse semantics
do {
var a = ["a", "b", "c"]
repeat {
print(a)
} while a.permute() != nil
}
// a possible upside> a possibly more natural consuming sequence (with no extra copies)
struct PermutationSequence<T: Comparable>: Sequence, IteratorProtocol {
private var current: [T]?
private var firstIteration = true
init(elements: [T]) {
self.current = elements.sorted()
}
mutating func next() -> [T]? {
if firstIteration {
firstIteration = false
return current
}
return current?.permute()
}
}
@hamishknight
Copy link

hamishknight commented Mar 29, 2017

The problem with this approach is that the iterator misses the first element of the iteration, e.g ["a", "b", "c"] due to the fact that it's calling permute on the first iteration and returning the result from that. May be simpler just to maintain a flag in the iterator to determine whether it's the first iteration (and then you can also just use the original implementation of permute that returns a Bool). Then you just have to skip calling permute on the first iteration – which allows you to avoid the copying too.

@dfrib
Copy link
Author

dfrib commented Mar 29, 2017

@hamishknight thanks! I even wrote in my comment that a check would be needed for first next() call, but I naturally forgot to include it in my implementation. (I'm Leaving the modified Array? returning implementation of permute() here as a start for discussion to my 2nd comment to the Q&A!).

@hamishknight
Copy link

@dfrib Ah, I totally missed that bit in your comment! Looks good now :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment