I\'m currently trying to make a Set of all possible combinations from an Array of Strings, were each element contains only one letter.
In your output example it wasn't clear what you really want, either:
all combinations and permutations of them:
["AB", "BA", "AC", "CA", "AD", "DA", ..., "ABCD", "ABDC", "ACBD", "ACDB", ...]
just all combinations:
["AB", "AC", "AD", "BC", "BD", "CD", "ABC", "ABD", ...]
I can recommend @oisdk's great Swift library: SwiftSequence for both of them, it has lots of useful functions. In the Combinations section he even shows an example of its usage with the Power Set, which is almost exactly what you're looking for in case 1. Upon importing the files of his library, you can create the powerSet function on CollectionTypes like this:
extension CollectionType {
func powerSet() -> LazySequence>>>{
var i = 0
return lazy.flatMap{ _ in self.lazyCombos(++i) }
}
}
This method evaluates lazily, which means that it's only evaluated when it really needs to. Now you mentioned that you only want to have combinations of at least 2 elements. This is easily done with the filter method:
let combinations = ["A", "B", "C", "D"].powerSet().filter{ $0.count >= 2 }
// As an array: [["A", "B"], ["A", "C"], ["A", "D"], ["B", "C"], ["B", "D"], ["C", "D"], ["A", "B", "C"], ["A", "B", "D"], ["A", "C", "D"], ["B", "C", "D"], ["A", "B", "C", "D"]]
For case 2. where you need permutations of those as well, you can do this:
let combPerms = combinations.flatMap{ $0.permutations() }
// As an array: [["A", "B"], ["B", "A"], ["A", "C"], ["C", "A"], ["A", "D"], ["D", "A"], ["B", "C"], ["C", "B"], ["B", "D"], ["D", "B"], ["C", "D"], ["D", "C"], ["A", "B", "C"], ["A", "C", "B"], ["B", "A", "C"], ["B", "C", "A"], ["C", "A", "B"], ["C", "B", "A"], ["A", "B", "D"], ["A", "D", "B"], ["B", "A", "D"], ["B", "D", "A"], ["D", "A", "B"], ["D", "B", "A"], ["A", "C", "D"], ["A", "D", "C"], ["C", "A", "D"], ["C", "D", "A"], ["D", "A", "C"], ["D", "C", "A"], ["B", "C", "D"], ["B", "D", "C"], ["C", "B", "D"], ["C", "D", "B"], ["D", "B", "C"], ["D", "C", "B"], ["A", "B", "C", "D"], ["A", "B", "D", "C"], ["A", "C", "B", "D"], ["A", "C", "D", "B"], ["A", "D", "B", "C"], ["A", "D", "C", "B"], ["B", "A", "C", "D"], ["B", "A", "D", "C"], ["B", "C", "A", "D"], ["B", "C", "D", "A"], ["B", "D", "A", "C"], ["B", "D", "C", "A"], ["C", "A", "B", "D"], ["C", "A", "D", "B"], ["C", "B", "A", "D"], ["C", "B", "D", "A"], ["C", "D", "A", "B"], ["C", "D", "B", "A"], ["D", "A", "B", "C"], ["D", "A", "C", "B"], ["D", "B", "A", "C"], ["D", "B", "C", "A"], ["D", "C", "A", "B"], ["D", "C", "B", "A"]]
You can convert these to a Set of Strings or an Array:
let array = Array(combPerms)
let set = Set(combPerms)
But I strongly recommend to use the lazy version ;) And yes, to remove duplicates you can just use Set(["A", "B", "C", "D"]) instead of just ["A", "B", "C", "D"]
You can also do case 2. in one go like this:
let x = ["A", "B", "C", "D"]
let result = Set(
x.indices
.flatMap{ x.lazyCombos($0 + 1) }
.filter{ $0.count >= 2 }
.flatMap{ $0.permutations() }
.map{ $0.joinWithSeparator("") })