Reputation: 9039
Simple question - hopefully, I am trying to generate a simple array of characters, something in the vein of:
// trying to do something like this (pseudo code):
let letters:[Character] = map(0..<26) { i in 'a' + i }
and have tried the following to no avail
let a = Character("a")
let z = Character("z")
let r:Range<Character> = a..<z
let letters:[Character] = map(a..<z) { i in i }
I realize that Swift uses Unicode, what is the correct way to do something like this?
(Note, this is not a question about interop with legacy Obj-C char, strictly in Swift for testing etc).
Upvotes: 21
Views: 25312
Reputation: 5569
One-liner: (combining compactMap and map)
let alphabet = (UnicodeScalar("a").value...UnicodeScalar("z").value).compactMap { UnicodeScalar($0) }.map { String($0) }
print(alphabet) // abcdefg....
Upvotes: 0
Reputation: 1868
This is a small refinement to @Mike S's answer. You can simply get the ASCII value of the first character in the English alphabet and iterate as follows.
let aScalars = ("a" as Character).asciiValue!
let letters: [Character] = (0..<26).map {
i in Character(UnicodeScalar(aScalars + i))
}
Complexity
Runtime: O(n)
Memory: O(n)
Where n is the total letters (Character
) in the
English alphabet.
Upvotes: 0
Reputation: 236370
Xcode 12.5 • Swift 5.4
extension ClosedRange where Bound == Unicode.Scalar {
static let asciiPrintable: ClosedRange = " "..."~"
var range: ClosedRange<UInt32> { lowerBound.value...upperBound.value }
var scalars: [Unicode.Scalar] { range.compactMap(Unicode.Scalar.init) }
var characters: [Character] { scalars.map(Character.init) }
var string: String { String(scalars) }
}
extension String {
init<S: Sequence>(_ sequence: S) where S.Element == Unicode.Scalar {
self.init(UnicodeScalarView(sequence))
}
}
let characters = ("a"..."z").characters // "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
let string = ("a"..."z").string // "abcdefghijklmnopqrstuvwxyz"
let range = ClosedRange.asciiPrintable // {lowerBound " ", upperBound "~"} 32...126
let characters = range.characters // [" ", "!", """, "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~"]
let string = range.string // " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
Upvotes: 13
Reputation: 4037
Swift 5, patch for @Mike S's
let aScalars = "a".unicodeScalars
let aCode = aScalars[aScalars.startIndex].value
let letters: [Character] = (0..<26).map {
i in
Character(Unicode.Scalar(aCode + i) ?? aScalars[aScalars.startIndex])
}
Upvotes: 2
Reputation: 25294
// MAKR: - ClosedRange extensions
extension ClosedRange where Bound == Unicode.Scalar {
var representationRange: ClosedRange<UInt32> { return lowerBound.value...upperBound.value }
var scalars: [Bound] { return representationRange.compactMap(Bound.init) }
}
extension ClosedRange where Bound == Character {
var scalars: [Unicode.Scalar]? {
guard lowerBound.unicodeScalars.count == 1, upperBound.unicodeScalars.count == 1 else { return nil }
return (lowerBound.unicodeScalars.first! ... upperBound.unicodeScalars.first!).scalars
}
var all: [Bound]? { return scalars?.map(Character.init) }
}
extension ClosedRange where Bound == String {
var scalars: [Unicode.Scalar]? {
guard lowerBound.unicodeScalars.count == 1, upperBound.unicodeScalars.count == 1,
let first = lowerBound.first, let last = upperBound.first else { return nil }
return (first...last).scalars
}
var all: [Bound]? { return scalars?.map(String.init) }
}
// MAKR: - Array extensions
extension Array where Element == Character {
init?(_ range: ClosedRange<Element>) {
guard let array = range.all else { return nil }
self = array
}
}
extension Array where Element == String {
init?(_ range: ClosedRange<Element>) {
guard let array = range.all else { return nil }
self = array
}
}
extension Array where Element == Unicode.Scalar { init(_ range: ClosedRange<Element>) { self = range.scalars } }
func test(value: Any) { print("-- \(type(of: value)) : \(value)") }
print("====================")
test(value: ("a"..."z").scalars ?? [])
test(value: ("a"..."z").all ?? [])
test(value: ("aa"..."z").all ?? [])
test(value: ("a"..."zz").all ?? [])
print("====================")
test(value: (Character("a")...Character("z")).scalars ?? [])
test(value: (Character("a")...Character("z")).all ?? [])
print("====================")
test(value: (Unicode.Scalar("a")...Unicode.Scalar("z")).scalars)
print("====================")
test(value: [Unicode.Scalar]("a"..."z"))
test(value: [Character]("a"..."z") ?? [])
test(value: [String]("a"..."z") ?? [])
test(value: [String]("aa"..."z") ?? [])
test(value: [String]("a"..."zz") ?? [])
====================
-- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<String> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<String> : []
-- Array<String> : []
====================
-- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<Character> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
====================
-- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
====================
-- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<Character> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<String> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<String> : []
-- Array<String> : []
extension Unicode.Scalar: Strideable {
public typealias Stride = Int
public func distance(to other: Unicode.Scalar) -> Stride { return abs(Int(value) - Int(other.value)) }
public func advanced(by n: Stride) -> Unicode.Scalar { return Unicode.Scalar(value + UInt32(n)) ?? self }
}
extension Character: Strideable {
public typealias Stride = Int
public func distance(to other: Character) -> Stride {
guard unicodeScalars.count == 1, other.unicodeScalars.count == 1 else { return 0 }
return unicodeScalars.first!.distance(to: other.unicodeScalars.first!)
}
public func advanced(by n: Stride) -> Character {
guard unicodeScalars.count == 1 else { return self }
return Character(unicodeScalars.first!.advanced(by: n))
}
}
extension Array where Element == String {
init?(_ range: ClosedRange<Element>) {
guard range.lowerBound.unicodeScalars.count == 1, range.upperBound.unicodeScalars.count == 1,
let first = range.lowerBound.unicodeScalars.first, let last = range.upperBound.unicodeScalars.first else { return nil }
self = [Unicode.Scalar](first...last).map(String.init)
}
}
func test(value: Any) { print("-- \(type(of: value)) : \(value)") }
test(value: [Unicode.Scalar]("a"..."z"))
test(value: [Character]("a"..."z"))
test(value: [String]("a"..."z"))
test(value: Array("a"..."z"))
test(value: Array(Character("a")...Character("z")))
test(value: Array(Unicode.Scalar("a")...Unicode.Scalar("z")))
-- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<Character> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Optional<Array<String>> : Optional(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"])
-- Optional<Array<String>> : Optional(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"])
-- Array<Character> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
Upvotes: 1
Reputation: 92479
With Swift 5, you can use the following Playground sample code in order to get an array of characters from a range of Unicode scalars:
// 1.
let unicodeScalarRange: ClosedRange<Unicode.Scalar> = "A" ... "Z"
// 2.
let unicodeScalarValueRange: ClosedRange<UInt32> = unicodeScalarRange.lowerBound.value ... unicodeScalarRange.upperBound.value
// 3.
let unicodeScalarArray: [Unicode.Scalar] = unicodeScalarValueRange.compactMap(Unicode.Scalar.init)
// 4.
let characterArray: [Character] = unicodeScalarArray.map(Character.init)
print(characterArray)
/*
prints: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
*/
Unicode.Scalar
's value
property
.As an alternative, you can use one of the sample codes below if you need to start from a range of Character
s or a range of String
s:
let unicodeScalarRange: ClosedRange<Character> = "A" ... "Z"
let unicodeScalarValueRange = unicodeScalarRange.lowerBound.unicodeScalars[unicodeScalarRange.lowerBound.unicodeScalars.startIndex].value ... unicodeScalarRange.upperBound.unicodeScalars[unicodeScalarRange.lowerBound.unicodeScalars.startIndex].value
let unicodeScalarArray = unicodeScalarValueRange.compactMap(Unicode.Scalar.init)
let characterArray = unicodeScalarArray.map(Character.init)
print(characterArray)
/*
prints: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
*/
let unicodeScalarRange: ClosedRange<String> = "A" ... "Z"
let unicodeScalarValueRange = unicodeScalarRange.lowerBound.unicodeScalars[unicodeScalarRange.lowerBound.unicodeScalars.startIndex].value ... unicodeScalarRange.upperBound.unicodeScalars[unicodeScalarRange.lowerBound.unicodeScalars.startIndex].value
let unicodeScalarArray = unicodeScalarValueRange.compactMap(Unicode.Scalar.init)
let characterArray = unicodeScalarArray.map(Character.init)
print(characterArray)
/*
prints: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
*/
Upvotes: 3
Reputation: 183
Solving for:
// trying to do something like this (pseudo code):
// let letters:[Character] = map(0..<26) { i in 'a' + i }
with Swift 4.2 / 5.0:
extension Character: Strideable {
public typealias Stride = Int
// https://stackoverflow.com/questions/39982335/creating-a-countableclosedrangecharacter
public func distance(to other: Character) -> Character.Stride {
let stride = Int(String(self).unicodeScalars.first!.value) - Int(String(other).unicodeScalars.first!.value)
return abs(stride)
}
public func advanced(by n: Character.Stride) -> Character {
return Character(UnicodeScalar(String(self).unicodeScalars.first!.value + UInt32(n))!)
}
}
extension ClosedRange where Element == Character {
var characters: [Character] { return Array(self) }
}
yields:
let letters: [Character] = ("A"..."Z").characters
print(letters)
// ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
Upvotes: 0
Reputation: 353
You can simply use
let alphabets: [UnicodeScalar] = Array("A"..."Z")
Upvotes: -4
Reputation: 1942
Thanks for useful answers.
I'm using one-liner version.
let xs = (97...122).map({Character(UnicodeScalar($0))})
or
let xs = (0..<26).map({Character(UnicodeScalar("a".unicodeScalars.first!.value + $0))})
Upvotes: 23
Reputation: 42325
It's a little cumbersome to get the initial character code (i.e. 'a'
in c / Obj-C) in Swift, but you can do it like this:
let aScalars = "a".unicodeScalars
let aCode = aScalars[aScalars.startIndex].value
let letters: [Character] = (0..<26).map {
i in Character(UnicodeScalar(aCode + i))
}
Upvotes: 23
Reputation: 19524
If you just want an array of a known set:
let str = "abcdefghijklmnopqrstuvwxyz"
let characterArray = Array(str)
println(characterArray)
//[a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z]
Upvotes: 10