Rotate Swift Array
I am trying to resolve this question I found on a website dedicated to coding using Swift 3.
I'm sure most of you have seen this before, but in case you're not here ...
The idea is that you take a string and rotate it x times. So using their example "12345" rotated 2x would be "34512"
I wrote this, but when I print it out on the Playground, it just prints out the exact same line I entered.
func rotateSring(originalString: String, numberOfRotations: Int) -> String {
var tempArray: [String] = []
tempArray.append(originalString)
let count = numberOfRotations
for _ in 1...count {
for letter in tempArray {
tempArray.remove(at: 0)
tempArray.append(letter)
}
}
let newString = tempArray.joined(separator: "")
return newString
}
I also tried the option
func rotateSring(originalString: String, numberOfRotations: Int) -> String {
var tempArray: [String] = []
tempArray.append(originalString)
let count = numberOfRotations
for _ in 1...count {
let test =tempArray.remove(at: 0)
tempArray.append(test)
}
let newString = tempArray.joined(separator: "")
return newString
}
It won't work if I say
let testRun = rotateSring(originalString: "12345", numberOfRotations: 2)
I want "34512" but instead I get "12345"
If I had to guess what I am doing wrong, I think I am just rotating the entire array from start to finish so that it moves, but it moves in a full circle.
If someone can explain what I am doing wrong and how I can fix it, that would be great. Thanks you
source to share
I went through your solution and found several errors. Executing below will work.
func rotateSring(originalString: String, numberOfRotations: Int) -> String {
var tempArray: [Character] = Array(originalString.characters)
let count = numberOfRotations
for _ in 1...count {
let letter = tempArray.removeFirst()
tempArray.append(letter)
}
let newString = String(tempArray)
return newString
}
let testRun = rotateSring(originalString: "12345", numberOfRotations: 2)
Now let me explain the changes:
var tempArray: [String] = []
tempArray.append(originalString)
// to
var tempArray: [Character] = Array(originalString.characters)
In Swift String
does not conform to the type protocol Sequence
, so you have to use an array Character
, and so when you tried to loop over letters
, you were actually iterating over the entire string i.e. 12345
...
// tempArray = ["12345"] not ["1", "2", "3", "4", "5"]
for letter in tempArray {
tempArray.remove(at: 0)
tempArray.append(letter)
}
source to share
func rotateSring(originalString: String, numberOfRotations: UInt) -> String {
if numberOfRotations == 0 {
return originalString
}
return rotateSring(originalString: originalString[originalString.index(after: originalString.startIndex)..<originalString.endIndex] + String(originalString[originalString.startIndex]),
numberOfRotations: numberOfRotations - 1)
}
source to share
What you are doing wrong in both attempts is that you used [String]
with only one element in it - originalString
. Therefore, when you remove the element at the index 0
, the array becomes empty.
Here is my solution:
func rotateSring(originalString: String, numberOfRotations: Int) -> String {
var str = originalString
for _ in 0..<numberOfRotations {
let firstChar = str.characters.first! // temporarily store the first char
var c = str.characters.dropFirst() // remove the first char from the string
c.append(firstChar) // add the first char back to the end
str.characters = c
}
return str
}
source to share
A custom row padding function can do this quite efficiently for you:
let string = "12345"
let rotation = 2
let rotated = "".padding(toLength: string.characters.count, withPad: string, startingAt: rotation % string.characters.count)
if you also need to maintain negative rotation values, you just need to calculate the corresponding positive offset:
let string = "12345"
let rotation = -3
let offset = ( rotation % string.characters.count + string.characters.count ) % string.characters.count
let rotated = "".padding(toLength: string.characters.count, withPad: string, startingAt: offset)
source to share
Rotation with substring(to:)
andsubstring(from:)
The accepted answer has already covered fixing your own solution; I'll add another alternative using substring(to:)
and to rotate a given string into a number of characters. The supplied one will be rotated left ( shift) for positive rotation numbers and rotated right for ( shift) for negative rotation numbers.substring(from:)
String
String
<-
->
// "left-rotate" supplied string using substring concenation
// (negative supplied rotations will be applied as "right-rotations")
func rotateString(originalString: String, numberOfRotations: Int) -> String {
// rotation is a non-changing operation upon empty or single-character strings
guard case let charCount = originalString.characters.count,
charCount > 1 else { return originalString }
// remove redundant full cycle rotation, and change rotation
// direction (left -> right) in case the supplied rotations are negative.
let numberOfRotations = numberOfRotations % charCount
+ (numberOfRotations < 0 ? 1 : 0) * charCount
// use substring methods to construct the "rotated" String
if numberOfRotations != 0 {
let splitIndex = originalString
.index(originalString.startIndex, offsetBy: numberOfRotations)
return originalString.substring(from: splitIndex) +
originalString.substring(to: splitIndex)
}
return originalString
}
Usage example:
let str = "1🇯🇵345"
// left rotations
print(rotateString(originalString: str, numberOfRotations: 1)) // 🇯🇵3451
print(rotateString(originalString: str, numberOfRotations: 2)) // 3451🇯🇵
print(rotateString(originalString: str, numberOfRotations: 6)) // 🇯🇵3451
// right rotations
print(rotateString(originalString: str, numberOfRotations: -2)) // 451🇯🇵3
print(rotateString(originalString: str, numberOfRotations: -6)) // 51🇯🇵34
// no rotations (/ only full cycles)
print(rotateString(originalString: str, numberOfRotations: 5)) // 1🇯🇵345
print(rotateString(originalString: str, numberOfRotations: -5)) // 1🇯🇵345
print(rotateString(originalString: str, numberOfRotations: 0)) // 1🇯🇵345
Or, as an extension String
:
extension String {
func rotated(by numberOfRotations: Int) -> String {
guard case let charCount = characters.count,
charCount > 1 else { return self }
let numberOfRotations = numberOfRotations % charCount
+ (numberOfRotations < 0 ? 1 : 0) * charCount
if numberOfRotations != 0 {
let splitIndex = index(startIndex, offsetBy: numberOfRotations)
return substring(from: splitIndex) + substring(to: splitIndex)
}
return self
}
}
/* example usage */
let str = "1🇯🇵345"
// left rotations
print(str.rotated(by: 1)) // 🇯🇵3451
print(str.rotated(by: 2)) // 3451🇯🇵
print(str.rotated(by: 6)) // 🇯🇵3451
// right rotations
print(str.rotated(by: -2)) // 451🇯🇵3
print(str.rotated(by: -6)) // 51🇯🇵34
// no rotations (/ only full cycles)
print(str.rotated(by: 5)) // 1🇯🇵345
print(str.rotated(by: -5)) // 1🇯🇵345
print(str.rotated(by: 0)) // 1🇯🇵345
source to share