programing

Swift에서 배열의 항목을 새 위치로 다시 정렬하는 방법은 무엇입니까?

elecom 2023. 8. 31. 23:39
반응형

Swift에서 배열의 항목을 새 위치로 다시 정렬하는 방법은 무엇입니까?

배열을 고려합니다.[1,2,3,4]배열 항목을 새 위치로 다시 정렬하려면 어떻게 해야 합니까?

예:

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].

Swift 3.0+:

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

및 함수 형태:

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:

그러면 3이 4번 위치에 놓입니다.

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

일반적인 기능도 만들 수 있습니다.

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
}

var arr입력 매개 변수를 지정하지 않고 변환할 수 없기 때문에 여기에 필요합니다.in-out하지만 우리의 경우 부작용이 없는 순수한 기능을 얻게 되는데, 제 생각에는 추론하기 훨씬 쉽습니다.그러면 다음과 같이 부를 수 있습니다.

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

모두 훌륭한 답변입니다!벤치마크 및 GIF 팬을 위한 성능과 보너스를 고려한 보다 완벽한 Swift 5 솔루션이 있습니다. ✌️

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

편집/업데이트:스위프트 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]

레오의 좋은 조언.

스위프트 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)
var arr = ["one", "two", "three", "four", "five"]

// Swap elements at index: 2 and 3
print(arr)
arr.swapAt(2, 3)
print(arr)

스위프트 5

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

스왑 방법을 사용하여 어레이의 항목을 스왑할 수 있습니다.

var arr = ["one", "two", "three", "four", "five"]

// Swap elements at index: 2 and 3
print(arr)
swap(&arr[2], &arr[3])
print(arr)

@ian은 좋은 솔루션을 제공했지만 어레이가 경계를 벗어나면 충돌할 것입니다. 추가로 확인하십시오.

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

배열의 경우 swift에 이동 기능이 없습니다.인덱스에서 개체를 제거하고 '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

Swift 4 - 항목 그룹을 이동하는 솔루션IndexSet인덱스를 그룹화하여 대상 인덱스로 이동합니다.에 대한 확장을 통해 실현됨RangeReplaceableCollection의 모든 항목을 제거하고 반환하는 방법을 포함합니다.IndexSet구성 기능을 유지하면서 정수보다 요소를 제한하는 것보다 확장을 더 일반화된 형태로 제한하는 방법을 잘 몰랐습니다.IndexSetsSwift Protocols에 대한 제 지식은 그렇게 광범위하지 않기 때문입니다.

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

다음은 어레이를 인플레이스로 변경하고 변경된 어레이를 반환하는 기능을 모두 갖춘 솔루션입니다.

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

macOS 10.15, iOS 14 이후로MutableCollection방법이 있습니다.move(fromOffsets:toOffset:).

https://developer.apple.com/documentation/swift/mutablecollection/move(fromoffsets:tooffset:)

Swift 4로 업데이트, 배열 인덱스 스와이프

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

효율적인 솔루션:

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

Swift 5 테스트 완료

케이크에 토핑을 추가하기 위해, 저는 처리할 기능을 추가했습니다.Array<Dictionary<String,Any>>

제 답변의 주요 출처는 여기 https://stackoverflow.com/a/50205000/4131763, 입니다.

여기 제 버전이 있습니다.

//Array+Extension.swift,
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 where Element == Dictionary<String, Any> {
    
    mutating func move(_ element:Element, to newIndex: Index) {
        if let oldIndex = self.firstIndex(where: { ($0.keys.first ?? "") == (element.keys.first ?? "") }) {
            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)
    }
}

사용 방법,

if let oldIndex = array.firstIndex(where: { ($0["ValidationTitle"] as! String) == "MEDICALNOTICEREQUIRED" }) {
                    let obj = array[oldIndex]
                    array.move(obj, to: array.startIndex)
                }
                
                if let oldIndex = array.firstIndex(where: { ($0["ValidationTitle"] as! String) == "HIGHRISKCONFIRMATION" }) {
                    let obj = array[oldIndex]
                    let oldIndexMEDICALNOTICEREQUIRED = array.firstIndex(where: { ($0["ValidationTitle"] as! String) == "MEDICALNOTICEREQUIRED" })!
                    array.move(obj, to: oldIndexMEDICALNOTICEREQUIRED + 1)
                }
                
                if let oldIndex = array.firstIndex(where: { ($0["ValidationTitle"] as! String) == "UNLICENCEDCONFIRMATION" }) {
                    let obj = array[oldIndex]
                    let oldIndexHIGHRISKCONFIRMATION = array.firstIndex(where: { ($0["ValidationTitle"] as! String) == "HIGHRISKCONFIRMATION" })!
                    array.move(obj, to: oldIndexHIGHRISKCONFIRMATION + 1)
                }

Leo Dabus의 솔루션은 훌륭하지만 전제 조건(!=에서 &&index.dll(!=에서 &&index.dll(to))을 사용하면 조건이 충족되지 않을 경우 앱이 충돌합니다.가드와 if문으로 변경했는데, 어떤 이유로 조건이 충족되지 않으면 아무 일도 일어나지 않고 앱이 계속 진행됩니다.앱이 손상될 수 있는 확장은 피해야 한다고 생각합니다.재배열 기능을 만들려면 Bool을 반환합니다. 성공하면 true이고 실패하면 false입니다.보다 안전한 솔루션:

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

기능(빠르지는 않지만 보편적인..조회/제거/삽입):

func c_move_to(var array:Array,var from:Int,var to:Int):

    var val = array[from]
    array.remove(from)
    array.insert(to,val)
    return array

사용 방법:

print("MOVE 0 to 3  [1,2,3,4,5]"  , c_move_to([1,2,3,4,5],0,3))
print("MOVE 1 to 2  [1,2,3,4,5]"  , c_move_to([1,2,3,4,5],1,2)) 

뱉기:

MOVE 0 to 3  [1,2,3,4,5][2, 3, 4, 1, 5]
MOVE 1 to 2  [1,2,3,4,5][1, 3, 2, 4, 5]

이 해결책은 어떻습니까?변경할 요소와 변경할 요소가 변경되었습니다.

// Extenstion

extension Array where Element: Equatable {
  mutating func change(_ element: Element, to newIndex: Index) {
    if let firstIndex = self.firstIndex(of: element) {
      self.insert(element, at: 0)
      self.remove(at: firstIndex + 1)
    }
  }
}

// Example

var testArray = ["a", "b", "c", "EE", "d"]
testArray.change("EE", to: 0)

// --> Result
// ["EE", "a", "b", "c", "d"]

언급URL : https://stackoverflow.com/questions/36541764/how-to-rearrange-item-of-an-array-to-new-position-in-swift

반응형