Rotate Array in Swift

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:

  1. Arrays with no elements and shifts producing the identity of the
    original array are returned immediately
  2. 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.
  3. 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.
  4. 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 manipulated offset (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



Leave a reply



Submit