Hoe kan ik een item van een array herschikken naar een nieuwe positie in Swift?

Beschouw de array [1,2,3,4]. Hoe kan ik het array-item herschikken naar een nieuwe positie.

Bijvoorbeeld:

put 3 into position 4 [1,2,4,3]

put 4 in to position 1 [4,1,2,3]

put 2 into position 3 [1,3,2,4].


Antwoord 1, autoriteit 100%

Swift 3.0+:

let element = arr.remove(at: 3)
arr.insert(element, at: 2)

en in functievorm:

func rearrange<T>(array: Array<T>, fromIndex: Int, toIndex: Int) -> Array<T>{
    var arr = array
    let element = arr.remove(at: fromIndex)
    arr.insert(element, at: toIndex)
    return arr
}

Swift 2.0:

Hierdoor komt 3 op positie 4.

let element = arr.removeAtIndex(3)
arr.insert(element, atIndex: 2)

Je kunt zelfs een algemene functie maken:

func rearrange<T>(array: Array<T>, fromIndex: Int, toIndex: Int) -> Array<T>{
    var arr = array
    let element = arr.removeAtIndex(fromIndex)
    arr.insert(element, atIndex: toIndex)
    return arr
}

De vararris hier nodig, omdat je de invoerparameter niet kunt muteren zonder op te geven dat deze in-outis. In ons geval krijgen we echter een pure functie zonder bijwerkingen, wat naar mijn mening een stuk gemakkelijker is om mee te redeneren.
Je zou het dan zo kunnen noemen:

let arr = [1,2,3,4]
rearrange(arr, fromIndex: 2, toIndex: 0) //[3,1,2,4]

Antwoord 2, autoriteit 45%

Allemaal geweldige antwoorden! Hier is een completere Swift 5-oplossing met prestatie in het achterhoofd en bonus voor benchmark- en GIF-fans. ✌️

extension Array where Element: Equatable
{
    mutating func move(_ element: Element, to newIndex: Index) {
        if let oldIndex: Int = self.firstIndex(of: element) { self.move(from: oldIndex, to: newIndex) }
    }
}
extension Array
{
    mutating func move(from oldIndex: Index, to newIndex: Index) {
        // Don't work for free and use swap when indices are next to each other - this
        // won't rebuild array and will be super efficient.
        if oldIndex == newIndex { return }
        if abs(newIndex - oldIndex) == 1 { return self.swapAt(oldIndex, newIndex) }
        self.insert(self.remove(at: oldIndex), at: newIndex)
    }
}

GIF


Antwoord 3, autoriteit 31%

bewerken/bijwerken: Swift 3.x

extension RangeReplaceableCollection where Indices: Equatable {
    mutating func rearrange(from: Index, to: Index) {
        precondition(from != to && indices.contains(from) && indices.contains(to), "invalid indices")
        insert(remove(at: from), at: to)
    }
}

var numbers = [1,2,3,4]
numbers.rearrange(from: 1, to: 2)
print(numbers)  // [1, 3, 2, 4]

Antwoord 4, autoriteit 17%

leuke tip van Leo.

voor Swift 3…5.5:

extension Array {  
    mutating func rearrange(from: Int, to: Int) {
        insert(remove(at: from), at: to)
    }
}
var myArray = [1,2,3,4]
myArray.rearrange(from: 1, to: 2)   
print(myArray)

Antwoord 5, autoriteit 14%

var arr = ["one", "two", "three", "four", "five"]
// Swap elements at index: 2 and 3
print(arr)
arr.swapAt(2, 3)
print(arr)

Antwoord 6, autoriteit 10%

Swift 4.2

extension Array where Element: Equatable {
    mutating func move(_ item: Element, to newIndex: Index) {
        if let index = index(of: item) {
            move(at: index, to: newIndex)
        }
    }
    mutating func bringToFront(item: Element) {
        move(item, to: 0)
    }
    mutating func sendToBack(item: Element) {
        move(item, to: endIndex-1)
    }
}
extension Array {
    mutating func move(at index: Index, to newIndex: Index) {
        insert(remove(at: index), at: newIndex)
    }
}

Antwoord 7, autoriteit 3%

We kunnen de swap-methode gebruiken om items in een array te wisselen:

var arr = ["one", "two", "three", "four", "five"]
// Swap elements at index: 2 and 3
print(arr)
swap(&arr[2], &arr[3])
print(arr)

Antwoord 8

@ian heeft een goede oplossing geboden, maar het zal crashen als de array buiten bereik raakt, controleer dat ook

extension Array where Element: Equatable {
    public mutating func move(_ element: Element, to newIndex: Index) {
        if let oldIndex: Int = index(of: element) {
            self.move(from: oldIndex, to: newIndex)
        }
    }
    public mutating func moveToFirst(item: Element) {
        self.move(item, to: 0)
    }
    public mutating func move(from oldIndex: Index, to newIndex: Index) {
        // won't rebuild array and will be super efficient.
        if oldIndex == newIndex { return }
        // Index out of bound handle here
        if newIndex >= self.count { return }
        // Don't work for free and use swap when indices are next to each other - this
        if abs(newIndex - oldIndex) == 1 { return self.swapAt(oldIndex, newIndex) }
        // Remove at old index and insert at new location
        self.insert(self.remove(at: oldIndex), at: newIndex)
    }
}

Antwoord 9

Er is geen verplaatsingsfunctionaliteit in swift voor arrays. je kunt een object bij een index nemen door het daar te verwijderen en het in je favoriete index plaatsen met ‘insert’

var swiftarray = [1,2,3,4]
let myobject = swiftarray.removeAtIndex(1) // 2 is the object at 1st index
let myindex = 3
swiftarray.insert(myobject, atIndex: myindex) // if you want to insert the    object to a particular index here it is 3
swiftarray.append(myobject) // if you want to move the object to last index

Antwoord 10

Swift 4– Oplossing voor het verplaatsen van een groep items uit een IndexSetindexen, groeperen en verplaatsen naar een bestemmingsindex. Gerealiseerd door een uitbreiding op RangeReplaceableCollection. Bevat een methode om alle items in een IndexSette verwijderen en terug te sturen. Ik wist niet zeker hoe ik de extensie moest beperken tot een meer algemene vorm dan om het element dan integer te beperken, terwijl ik de mogelijkheid behield om IndexSetste construeren, aangezien mijn kennis van Swift-protocollen niet zo uitgebreid is.

extension RangeReplaceableCollection where Self.Indices.Element == Int {
    /**
        Removes the items contained in an `IndexSet` from the collection.
        Items outside of the collection range will be ignored.
        - Parameter indexSet: The set of indices to be removed.
        - Returns: Returns the removed items as an `Array<Self.Element>`.
    */
    @discardableResult
    mutating func removeItems(in indexSet: IndexSet) -> [Self.Element] {
        var returnItems = [Self.Element]()
        for (index, _) in self.enumerated().reversed() {
            if indexSet.contains(index) {
                returnItems.insert(self.remove(at: index), at: startIndex)
            }
        }
        return returnItems
    }
    /**
        Moves a set of items with indices contained in an `IndexSet` to a     
        destination index within the collection.
        - Parameters:
            - indexSet: The `IndexSet` of items to move.
            - destinationIndex: The destination index to which to move the items.
        - Returns: `true` if the operation completes successfully else `false`.
        If any items fall outside of the range of the collection this function 
        will fail with a fatal error.
    */
    @discardableResult
    mutating func moveItems(from indexSet: IndexSet, to destinationIndex: Index) -> Bool {
        guard indexSet.isSubset(of: IndexSet(indices)) else {
            debugPrint("Source indices out of range.")
            return false
            }
        guard (0..<self.count + indexSet.count).contains(destinationIndex) else {
            debugPrint("Destination index out of range.")
            return false
        }
        let itemsToMove = self.removeItems(in: indexSet)
        let modifiedDestinationIndex:Int = {
            return destinationIndex - indexSet.filter { destinationIndex > $0 }.count
        }()
        self.insert(contentsOf: itemsToMove, at: modifiedDestinationIndex)
        return true
    }
}

Antwoord 11

Hier is een oplossing met functies om zowel de array ter plaatse te wijzigen als een gewijzigde array terug te geven:

extension Array {
    func rearranged(from fromIndex: Int, to toIndex: Int) -> [Element] {
        var arr = self
        let element = arr.remove(at: fromIndex)
        if toIndex >= self.count {
            arr.append(element)
        } else {
            arr.insert(element, at: toIndex)
        }
        return arr
    }
    mutating func rearrange(from fromIndex: Int, to toIndex: Int) {
        let element = self.remove(at: fromIndex)
        if toIndex >= self.count {
            self.append(element)
        } else {
            self.insert(element, at: toIndex)
        }
    }
}

Antwoord 12

Update met Swift 4,
Swipe-array-index

for (index,addres) in self.address.enumerated() {
     if addres.defaultShipping == true{
          let defaultShipping = self.address.remove(at: index)
          self.address.insert(defaultShipping, at: 0)
     }
}

Antwoord 13

Efficiënte oplossing:

extension Array 
{
    mutating func move(from sourceIndex: Int, to destinationIndex: Int)
    {
        guard
            sourceIndex != destinationIndex
            && Swift.min(sourceIndex, destinationIndex) >= 0
            && Swift.max(sourceIndex, destinationIndex) < count
        else {
            return
        }
        let direction = sourceIndex < destinationIndex ? 1 : -1
        var sourceIndex = sourceIndex
        repeat {
            let nextSourceIndex = sourceIndex + direction
            swapAt(sourceIndex, nextSourceIndex)
            sourceIndex = nextSourceIndex
        }
        while sourceIndex != destinationIndex
    }
}

Antwoord 14

func adjustIndex(_ index: Int, forRemovalAt removed: Int) -> Int {
    return index <= removed ? index : index - 1
}
extension Array
{
    mutating func move(from oldIndex: Index, to newIndex: Index) {
        insert(remove(at: oldIndex), at: adjustIndex(newIndex, forRemovalAt: oldIndex))
    }
}

Antwoord 15

De oplossing van Leo Dabus is geweldig, maar het gebruik van precondition(from != to && indices.contains(from != to && indices.contains(to), “ongeldige indexen”), zal de app crashen als er wordt niet aan de voorwaarden voldaan. Ik heb het gewijzigd in guard en een if-statement – als om de een of andere reden niet aan de voorwaarden wordt voldaan, gebeurt er niets en gaat de app door. Ik denk dat we moeten voorkomen dat we extensies maken die de app kunnen laten crashen. Als je wilt zou ervoor kunnen zorgen dat de functie herschikken een Bool retourneert – waar als het is gelukt en onwaar als het niet is gelukt.
De veiligere oplossing:

extension Array {
mutating func rearrange(from: Int, to: Int) {
    guard from != to else { return }
    //precondition(from != to && indices.contains(from) && indices.contains(to), "invalid indexes")
    if indices.contains(from) && indices.contains(to) {
        insert(remove(at: from), at: to)
    }
}

Other episodes