Rotate Array in Swift
Edit update:
Swift 5 or later
extension RangeReplaceableCollection {
func rotatingLeft(positions: Int) -> SubSequence {
let index = self.index(startIndex, offsetBy: positions, limitedBy: endIndex) ?? endIndex
return self[index...] + self[..<index]
}
mutating func rotateLeft(positions: Int) {
let index = self.index(startIndex, offsetBy: positions, limitedBy: endIndex) ?? endIndex
let slice = self[..<index]
removeSubrange(..<index)
insert(contentsOf: slice, at: endIndex)
}
}
extension RangeReplaceableCollection {
func rotatingRight(positions: Int) -> SubSequence {
let index = self.index(endIndex, offsetBy: -positions, limitedBy: startIndex) ?? startIndex
return self[index...] + self[..<index]
}
mutating func rotateRight(positions: Int) {
let index = self.index(endIndex, offsetBy: -positions, limitedBy: startIndex) ?? startIndex
let slice = self[index...]
removeSubrange(index...)
insert(contentsOf: slice, at: startIndex)
}
}
var test = [1,2,3,4,5,6,7,8,9,10]
test.rotateLeft(positions: 3) // [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]
var test2 = "1234567890"
test2.rotateRight(positions: 3) // "8901234567"
Rotate Swift Array
I have gone through your solution and found few mistakes. The below implementation 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
doesn't conform to Sequence
type protocol and so you need to use Character
array and so when you were trying to loop over letters
, you were actually looping over the whole string i.e. 12345
.
// tempArray = ["12345"] not ["1", "2", "3", "4", "5"]
for letter in tempArray {
tempArray.remove(at: 0)
tempArray.append(letter)
}
Shift Swift Array
Short & clear Swift 3 & 4 solution I came up with:
extension Array {
func shifted(by shiftAmount: Int) -> Array<Element> {
// 1
guard self.count > 0, (shiftAmount % self.count) != 0 else { return self }
// 2
let moduloShiftAmount = shiftAmount % self.count
let negativeShift = shiftAmount < 0
let effectiveShiftAmount = negativeShift ? moduloShiftAmount + self.count : moduloShiftAmount
// 3
let shift: (Int) -> Int = { return $0 + effectiveShiftAmount >= self.count ? $0 + effectiveShiftAmount - self.count : $0 + effectiveShiftAmount }
// 4
return self.enumerated().sorted(by: { shift($0.offset) < shift($1.offset) }).map { $0.element }
}
}
Explanation:
- Arrays with no elements and shifts producing the identity of the
original array are returned immediately - To get the effective shift amount regardless of the amount passed with the function, we do some modulo calculation to get rid of shifts that would rotate the elements in the array more than once (e.g. in an Array with 5 Objects, a shift of +7 is the same as a shift of +2). Since we always want to shift to the right, in order to be done with one simple function instead of two, negative inputs have to be dealt with (e.g. in an Array with 5 Objects, a shift of -2 is the same as a shift of +3). Therefore we adjust the negative results of the modulo calculation by the length of the array.
Of course those 3 lines could be done in one, but I wanted to make this as readable as possible. - Now we prepare the actual shift by taking the index (
$0
) of element and returning the shifted index by adding the amount calculated in step 2. If the new index lands outside of the array length, it needs to be wrapped around to the front. - And finally we apply all the preparation to our array with some trickery:
enumerated()
gives us an array of tuples[(offset: Int, element: Int)]
, which is simply the original index of every element and the element itself. We then sort this enumerated array by the manipulatedoffset
(aka the element's index) via applying the function from step 3. Lastly we get rid of the enumeration by mapping the sorted elements back into an array.
This extension works with arrays of any type. Examples:
let colorArray = [
UIColor.red,
UIColor.orange,
UIColor.yellow,
UIColor.green,
UIColor.blue
]
let shiftedColorArray = [
UIColor.green,
UIColor.blue,
UIColor.red,
UIColor.orange,
UIColor.yellow
]
colorArray.shifted(by: 2) == shiftedColorArray // returns true
[1,2,3,4,5,6,7].shifted(by: -23) // returns [3,4,5,6,7,1,2]
Shift elements in array by index
You can use ranged subscripting and concatenate the results. This will give you what you're looking for, with names similar to the standard library:
extension Array {
func shiftRight(var amount: Int = 1) -> [Element] {
guard count > 0 else { return self }
assert(-count...count ~= amount, "Shift amount out of bounds")
if amount < 0 { amount += count } // this needs to be >= 0
return Array(self[amount ..< count] + self[0 ..< amount])
}
mutating func shiftRightInPlace(amount: Int = 1) {
self = shiftRight(amount)
}
}
Array(1...10).shiftRight()
// [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]
Array(1...10).shiftRight(7)
// [8, 9, 10, 1, 2, 3, 4, 5, 6, 7]
Instead of subscripting, you could also return Array(suffix(count - amount) + prefix(amount))
from shiftRight()
.
How do I perform a circular shift in Swift?
You can achieve this with two bit shift operators and a bitwise OR:
func circularRightShift(_ input: UInt8, _ amount: UInt8) -> UInt8 {
let amount = amount % 8 // Reduce to the range 0...7
return (input >> amount) | (input << (8 - amount))
}
Example (amount=5):
abcdefgh <- bits of input
00000abc <- bits of input >> amount
defgh000 <- bits of input << (8 - amount)
defghabc <- bits of result
How do you rotate a two dimensional array?
Here it is in C#
int[,] array = new int[4,4] {
{ 1,2,3,4 },
{ 5,6,7,8 },
{ 9,0,1,2 },
{ 3,4,5,6 }
};
int[,] rotated = RotateMatrix(array, 4);
static int[,] RotateMatrix(int[,] matrix, int n) {
int[,] ret = new int[n, n];
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
ret[i, j] = matrix[n - j - 1, i];
}
}
return ret;
}
Related Topics
Swift: How to Change a Property's Value Without Calling Its Didset Function
How to Make Rounded Corner Progress Bar in Swift
Sending a Parameter Argument to Function Through Uitapgesturerecognizer Selector
Firebase Sign Out Not Working in Swift
How to Make Firebase Database Data the Data Source for Uicollection View
Scenekit - Animation with Dae File Format
Using Nstimer in Swift Playground
Understanding the Removerange(_:) Documentation
Masking Uiview/Uiimageview to Cutout Transparent Text
My Data Changes in Uitableviewcell When I Scroll Down and Get Back
How to Continue Ble Activities Onto Next View Controller
Check for Nil with Guard Instead of If
Argument for Generic Parameter Could Not Be Inferred
Which Swift Character Count Should I Use When Interacting with Nsstring APIs
Aws S3 Transfer Manager ${Cognito-Identity.Amazonaws.Com:Sub} Policy Variable Access Denied