40

I have one simple array like:

var cellOrder = [1,2,3,4]

I want to exchange elements like suppose a second element with first element.

And result will be:

[2,1,3,4]

I know we can use exchangeObjectAtIndex with NSMutableArray But I want to use swift array. Any ways to do same with swift [Int] array?

Dharmesh Kheni
  • 71,228
  • 33
  • 160
  • 165
  • 6
    You should know about `swap()` because *you* posted a question about it: [fatal error: swapping a location with itself is not supported with Swift 2.0](http://stackoverflow.com/questions/32689753/fatal-error-swapping-a-location-with-itself-is-not-supported-with-swift-2-0) – Martin R Nov 03 '15 at 18:06

5 Answers5

68

Use swap:

var cellOrder = [1,2,3,4]
swap(&cellOrder[0], &cellOrder[1])

Alternately, you can just assign it as a tuple:

(cellOrder[0], cellOrder[1]) = (cellOrder[1], cellOrder[0])
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • 10
    In swift 4 it's now `swapAt` – Rishab Sep 18 '17 at 14:29
  • 1
    `swapAt` is a different function that takes indexes rather than `inout` values. It can be be used to solve this problem too, but is not a replacement for `swap` (which still exists in Swift 4). – Rob Napier Sep 18 '17 at 14:34
  • 2
    I had issues implementing this answer. I got this particular error while trying to swap out values. "Simultaneous accesses to 0x108e19918, but modification requires exclusive access." use `swap` worked better for me. – Karthik Kannan Jan 15 '18 at 12:03
  • To expand on what the people above are saying, instead of doing 'swap(&cellOrder[0], &cellOrder[1])' in Swift 4 you would now do 'swapAt(0, 1)', so it's simpler now. And @RobNapier's second solution still works in Swift 4: you can still get the job done by assigning it as a tuple. – Adam Feb 02 '18 at 16:51
  • Can you give an example of where `swap` can be applied but `swap(at:)` can't? – mfaani Mar 29 '18 at 17:16
  • 1
    @Honey Any case where it's not a Collection. `swap(&x, &y)`. – Rob Napier Mar 29 '18 at 18:05
  • @RobNapier you say "[swapAt] is not a replacement for swap"... in cases where it is available, it is 100% interchangeable right? – Dan Rosenstark Apr 26 '19 at 12:15
  • I'm not sure what you mean by "where it's available." The two functions have different interfaces. They don't do the same things. – Rob Napier Apr 26 '19 at 13:47
51

Swift 4

swapAt(_:_:):

cellOrder.swapAt(index0, index1)
Ahmad F
  • 30,560
  • 17
  • 97
  • 143
hstdt
  • 5,652
  • 2
  • 34
  • 34
  • 1
    This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - [From Review](/review/low-quality-posts/16686681) – basvk Jul 13 '17 at 11:26
  • 3
    @basvk I think it answers the question - it shows how to "swap two elements" from the array. And it's a valid answer to the question (also correct). – Zizouz212 Jul 13 '17 at 21:55
  • 1
    @basvk Thanks for your advise.To answer this question,`cellOrder.swapAt(0, 1)`should be better to understand. And also thanks @Zizouz212 . – hstdt Jul 14 '17 at 10:02
  • 2
    Yes this is valid answer for swift 4.0 version. – Paresh Patel Aug 01 '17 at 11:42
8

One option is:

cellOrder[0...1] = [cellOrder[1], cellOrder[0]]
Hermann Klecker
  • 14,039
  • 5
  • 48
  • 71
4

Details

  • Xcode Version 10.3 (10G8), Swift 5

Base (unsafe but fast) variant

unsafe - means that you can catch fatal error when you will try to make a swap using wrong (out of the range) index of the element in array

var array = [1,2,3,4]
// way 1
(array[0],array[1]) = (array[1],array[0])
// way 2
array.swapAt(2, 3)

print(array)

Solution of safe swap

  • save swap attempt (checking indexes)
  • possible to know what index wrong

do not use this solution when you have to swap a lot of elements in the loop. This solution validates both (i,j) indexes (add some extra logic) in the swap functions which will make your code slower than usage of standard arr.swapAt(i,j). It is perfect for single swaps or for small array. But, if you will decide to use standard arr.swapAt(i,j) you will have to check indexes manually or to be sure that indexes are not out of the range.

import Foundation

enum SwapError: Error {
    case wrongFirstIndex
    case wrongSecondIndex
}

extension Array {
    mutating func detailedSafeSwapAt(_ i: Int, _ j: Int) throws {
        if !(0..<count ~= i) { throw SwapError.wrongFirstIndex }
        if !(0..<count ~= j) { throw SwapError.wrongSecondIndex }
        swapAt(i, j)
    }

    @discardableResult mutating func safeSwapAt(_ i: Int, _ j: Int) -> Bool {
        do {
            try detailedSafeSwapAt(i, j)
            return true
        } catch {
            return false
        }
    }
}

Usage of safe swap

result = arr.safeSwapAt(5, 2)

//or
if arr.safeSwapAt(5, 2) {
    //Success
} else {
    //Fail
}

//or
arr.safeSwapAt(4, 8)

//or
do {
    try arr.detailedSafeSwapAt(4, 8)
} catch let error as SwapError {
    switch error {
    case .wrongFirstIndex: print("Error 1")
    case .wrongSecondIndex: print("Error 2")
    }
}

Full sample of safe swap

var arr = [10,20,30,40,50]
print("Original array: \(arr)")

print("\nSample 1 (with returning Bool = true): ")
var result = arr.safeSwapAt(1, 2)
print("Result: " + (result ? "Success" : "Fail"))
print("Array: \(arr)")

print("\nSample 2 (with returning Bool = false):")
result = arr.safeSwapAt(5, 2)
print("Result: " + (result ? "Success" : "Fail"))
print("Array: \(arr)")

print("\nSample 3 (without returning value):")
arr.safeSwapAt(4, 8)
print("Array: \(arr)")

print("\nSample 4 (with catching error):")
do {
    try arr.detailedSafeSwapAt(4, 8)
} catch let error as SwapError {
    switch error {
    case .wrongFirstIndex: print("Error 1")
    case .wrongSecondIndex: print("Error 2")
    }
}
print("Array: \(arr)")


print("\nSample 5 (with catching error):")
do {
    try arr.detailedSafeSwapAt(7, 1)
} catch let error as SwapError {
    print(error)
}
print("Array: \(arr)")

Full sample log of safe swap

Original array: [10, 20, 30, 40, 50]

Sample 1 (with returning Bool = true): 
Result: Success
Array: [10, 30, 20, 40, 50]

Sample 2 (with returning Bool = false):
Result: Fail
Array: [10, 30, 20, 40, 50]

Sample 3 (without returning value):
Array: [10, 30, 20, 40, 50]

Sample 4 (with catching error):
Error 2
Array: [10, 30, 20, 40, 50]

Sample 5 (with catching error):
wrongFirstIndex
Array: [10, 30, 20, 40, 50]
Vasily Bodnarchuk
  • 24,482
  • 9
  • 132
  • 127
1

Use swapAt method,

var arr = [10,20,30,40,50]
arr.swapAt(2, 3)

Use the index to swap element.