4
\$\begingroup\$

Task:

Write a function which rotates all elements of a given array to the right.

Example: [1, 2, 3] => [3, 1, 2]

My solution:

func rotateRight(array ary: [Int]) -> [Int] {    guard ary.isEmpty == false else {        return ary    }        var copy = ary    let last = ary.last        var i = ary.count - 1        while i > 0 {        copy[i] = copy[i - 1]        i -= 1    }        copy[0] = last!        return copy}var ary1 = [1, 2, 3]print(rotateRight(array: ary1)) // [3, 1, 2]var ary2 = [1, 1, 2, 3, 3, 4]print(rotateRight(array: ary2)) // [4, 1, 1, 2, 3, 3]var ary3 = [Int]()print(rotateRight(array: ary3)) // []var ary4 = [1]print(rotateRight(array: ary4)) // [1]

I have to make a copy of the array because Swift-parameter are immutable.Do I handle the issue in a proper way? Or should it be done differently?

Is there a better way to solve the described task?

toolic's user avatar
toolic
16.4k6 gold badges29 silver badges220 bronze badges
askedDec 28, 2024 at 7:12
michael.zech's user avatar
\$\endgroup\$
2
  • 1
    \$\begingroup\$guard let last = ary.last else { return ary }; return [last] + ary.dropLast()\$\endgroup\$CommentedDec 28, 2024 at 18:53
  • 1
    \$\begingroup\$return ary.isEmpty ? ary : ary.suffix(1) + ary.prefix(ary.count - 1)\$\endgroup\$CommentedDec 28, 2024 at 18:55

1 Answer1

2
\$\begingroup\$

A comparison againsttrue orfalse is never needed,ary.isEmpty == false is more concisely expressed as!ary.isEmpty.

Here I would not use aguard statement at all. That statement was introduced to get rid of the “if-let pyramid of doom,” to unwrap a variable without introducing another scope/indentation level. But I would not use aguard statement for every “early return” situation, in particular not if it makes the statement look like a double negation.

if ary.isEmpty {    return ary}

is shorter and clearer in my opinion. Alternatively one can use optional binding

if let last = ary.last {    // ...} else {    return ary}

to test for a non-empty arrayand get the last element in one step, that allows to get rid of the ugly forced unwrapcopy[0] = last! in your code.

As already mentioned in the comment, arrayslicing methods can be used instead of copying all elements to their new place:

if let last = ary.last {    return [last] + ary.dropLast()} else {    return ary}

Another option is to concatenate two array slices, this can easily be generalized to shifting array elements by more than one position to the right or left:

if ary.isEmpty {    return ary}let frontIndex = ary.count - 1return Array(ary[frontIndex...]) + ary[0..<frontIndex]

Naming: The parameter nameary reminds my of unary/binary/arity and is not significantly shorter thanarray. My suggestion is to usearray with an empty argument label:

func rotateRight(_ array: [Int]) -> [Int] {    // ...    }var array1 = [1, 2, 3]print(rotateRight(array1)) // [3, 1, 2]

Of course, if you don't want to reinvent the wheel then you can simply use therotate(toStartAt:) method of theswift-algorithms package.

answeredDec 29, 2024 at 14:06
Martin R's user avatar
\$\endgroup\$

You mustlog in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.