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

+3


source to share


5 answers


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)
  }

      

+3


source


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)
}

      



+3


source


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
}

      

+1


source


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)

      

+1


source


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

      

0


source







All Articles