How can I split the given String
in Swift into groups with given length, reading from right to left?
For example, I have string 123456789
a
Another solution using substrings:
func splitStringByIntervals(str: String, interval: Int) -> [String] {
let st = String(str.characters.reverse())
let length = st.characters.count
var groups = [String]()
for (var i = 0; i < length; i += interval) {
groups.append((st as NSString).substringWithRange(NSRange(location: i, length: min(interval, length - i))))
}
return groups.map{ String($0.characters.reverse())}.reverse()
}
The output for :
for element in splitStringByIntervals("1234567", interval: 3) {
print(element)
}
is:
1
234
567
I made something like this, couldn't create anything better looking, but its result matches the question:
func splitedString(string: String, lenght: Int) -> [String] {
var result = [String](), count = 0, line = ""
for c in string.characters.reverse() {
count++; line.append(c)
if count == lenght {count = 0; result.append(String(line.characters.reverse())); line = ""}
}
if !line.isEmpty {result.append(String(line.characters.reverse()))}
return result.reverse()
}
Just to add my entry to this very crowded contest (SwiftStub):
func splitedString(string: String, length: Int) -> [String] {
var result = [String]()
for var i = 0; i < string.characters.count; i += length {
let endIndex = string.endIndex.advancedBy(-i)
let startIndex = endIndex.advancedBy(-length, limit: string.startIndex)
result.append(string[startIndex..<endIndex])
}
return result.reverse()
}
Or if you are feeling functional-y:
func splitedString2(string: String, length: Int) -> [String] {
return 0.stride(to: string.characters.count, by: length)
.reverse()
.map {
i -> String in
let endIndex = string.endIndex.advancedBy(-i)
let startIndex = endIndex.advancedBy(-length, limit: string.startIndex)
return string[startIndex..<endIndex]
}
}
There's probably a more elegant solution, but this works:
func splitedString(string: String, length: Int) -> [String] {
let string = Array(string.characters)
let firstGroupLength = string.count % length
var result: [String] = []
var group = ""
if firstGroupLength > 0 {
for i in 0..<firstGroupLength {
group.append(string[i])
}
result.append(String(group))
group = ""
}
for i in firstGroupLength..<string.count {
group.append(string[i])
if group.characters.count == length {
result.append(group)
group = ""
}
}
return result
}
splitedString("abcdefg", length: 2) // ["a", "bc", "de", "fg"]
splitedString("1234567", length: 3) // ["1", "234", "567"]
func split(every length:Int) -> [Substring] {
guard length > 0 && length < count else { return [suffix(from:startIndex)] }
return (0 ... (count - 1) / length).map { dropFirst($0 * length).prefix(length) }
}
func split(backwardsEvery length:Int) -> [Substring] {
guard length > 0 && length < count else { return [suffix(from:startIndex)] }
return (0 ... (count - 1) / length).map { dropLast($0 * length).suffix(length) }.reversed()
}
Tests:
XCTAssertEqual("0123456789".split(every:2), ["01", "23", "45", "67", "89"])
XCTAssertEqual("0123456789".split(backwardsEvery:2), ["01", "23", "45", "67", "89"])
XCTAssertEqual("0123456789".split(every:3), ["012", "345", "678", "9"])
XCTAssertEqual("0123456789".split(backwardsEvery:3), ["0", "123", "456", "789"])
XCTAssertEqual("0123456789".split(every:4), ["0123", "4567", "89"])
XCTAssertEqual("0123456789".split(backwardsEvery:4), ["01", "2345", "6789"])
Here's an another version with Functional Programming.
extension String{
func splitedString(length: Int) -> [String]{
guard length > 0 else { return [] }
let range = 0..<((characters.count+length-1)/length)
let indices = range.map{ length*$0..<min(length*($0+1),characters.count) }
return indices
.map{ characters.reverse()[$0.startIndex..<$0.endIndex] }
.map( String.init )
}
}
"1234567890".splitedString(3)