Problem
I'm trying to find all of the possible combinations of capitalization for a String in Swift. For example, given the String
"abc", I would want my method to return an Array
of String
s, like this: ["Abc", "aBc", "abC", "ABc", "abc", "ABC", "aBC", "AbC"]
. The formula for the possible number of capitalization combinations is like this:
2i
where i
is the number of Characters
in the String
.
Attempted Solutions
I've tried the following function, via an extension to the String
type:
extension String {
func allPossibleCombinations() -> [String] {
let string = self
var result = [String]()
var current = string
result.append(current)
for i in 0..<string.count {
let index = string.index(string.startIndex, offsetBy: i)
if string[index].isLetter {
current = current.replacingCharacters(in: index...index, with: String(current[index]).uppercased())
result.append(current)
}
}
return result
}
}
This didn't work because it only returns capitalizations in order. For example, if I were to call this method on the String
"abc"
, it would return
["abc", "Abc", "ABc", "ABC"]
This should produce, as stated above, 8 different Strings
. I suspect that I need to factor in an exponent to my code, or potentially some form of randomly choosing a Character
.
Similar questions that are NOT duplicates
- This
Python
question discusses the same issue: Find all upper, lower and mixed case combinations of a string. However, this does not work for my issue because it is inPython
, notSwift
. - This
JavaScript
question talks about finding all combinations of aString
: Find all the combinations of a string Javascript. However, this is about general combinations, not capitalization ones, and is also in the wrong language. - This
JavaScript
question discusses the same issue: Find all lowercase and uppercase combinations of a string in Javascript. However, this is inJavaScript
, notSwift
. - This
C
question deals with the same issue: Finding all capital letter combinations of random text. However, it is inC
, notSwift
.
Summary
I am trying to make a function to get all possible capitalization forms of a String
. I have a current attempt, but it is not sufficient as it does not produce all possible options.
CodePudding user response:
Compute the integers in the range 0 ..< 2^length
and use the bits of the binary representation to tell you when to capitalize a letter:
extension String {
func allPossibleCombinations() -> [String] {
guard self.count > 0 else { return [] }
var result = [String]()
let lower = self.lowercased().map(String.init)
let upper = self.uppercased().map(String.init)
let length = self.count
let limit = 1 << length
for n in 0..<limit {
var word = ""
for i in 0..<length {
if n & (1 << (length - i - 1)) != 0 {
word = upper[i]
} else {
word = lower[i]
}
}
result.append(word)
}
return result
}
}
Examples
print("abc".allPossibleCombinations())
// ["abc", "abC", "aBc", "aBC", "Abc", "AbC", "ABc", "ABC"]
print("abcd".allPossibleCombinations())
// ["abcd", "abcD", "abCd", "abCD", "aBcd", "aBcD", "aBCd", "aBCD", "Abcd", "AbcD", "AbCd", "AbCD", "ABcd", "ABcD", "ABCd", "ABCD"]
Alex's Swifty Version
In the comments, Alex added this Swifty version using nested maps:
extension String {
func allPossibleCombinations() -> [String] {
guard self.count > 0 else { return [] }
let length = self.count
let limit = 1 << self.count
return (0..<limit) .map { n in
return self.enumerated()
.map { i, c in (n & (1 << (length - i - 1)) != 0) ? c.uppercased() : c.lowercased() }
.joined()
}
}
}
CodePudding user response:
You could follow a recursive approach:
func capitalizations(of string: String) -> [String] {
guard let first = string.first else { return [] }
let firstLowercase = first.lowercased()
let firstUppercase = first.uppercased()
if string.count == 1 {
return [firstLowercase, firstUppercase]
} else {
let partial = capitalizations(of: String(string.dropFirst()))
return partial.map { firstLowercase $0 } partial.map { firstUppercase $0 }
}
}
print(capitalizations(of: "abc"))
// ["abc", "abC", "aBc", "aBC", "Abc", "AbC", "ABc", "ABC"]
Just take the first character, lowercase and uppercase it, and prepend it to capitalizations for the rest of the string.
CodePudding user response:
Use uniquePermutations
.
import Algorithms
extension String {
var capitalizationCombinations: [Self] {
[false, true].flatMap {
capitalize in repeatElement(capitalize, count: count)
}
.uniquePermutations(ofCount: count)
.map { [lowercased = lowercased()] capitalizes in
.init(
zip(lowercased, capitalizes).map { character, capitalize in
capitalize ? character.uppercased().first! : character
}
)
}
}