Arrays 如何在Swift中迭代移动数组中的项目

Arrays 如何在Swift中迭代移动数组中的项目,arrays,swift,sorting,Arrays,Swift,Sorting,假设我们有一个数组: var-sphabet=[“B”、“C”、“D”、“E”、“H”、“F”、“G”、“A”] 我们希望通过移动两个项对其进行排序:第7项(“A”)到位置0,第4项(“H”)到位置7,用元组数组描述: var移动=[(7,0)、(4,7)] 因此,期望的结果是: [“A”、“B”、“C”、“D”、“E”、“F”、“G”、“H”] 这很容易用以下方法解决: var scrambledAlphabet = ["B", "C", "D", "E", "H", "F", "G", "A

假设我们有一个数组:

var-sphabet=[“B”、“C”、“D”、“E”、“H”、“F”、“G”、“A”]

我们希望通过移动两个项对其进行排序:第7项(“A”)到位置0,第4项(“H”)到位置7,用元组数组描述:

var移动=[(7,0)、(4,7)]

因此,期望的结果是:

[“A”、“B”、“C”、“D”、“E”、“F”、“G”、“H”]

这很容易用以下方法解决:

var scrambledAlphabet = ["B", "C", "D", "E", "H", "F", "G", "A"]
var moves = [(7, 0), (4, 7)]

for (i, j) in moves  {
    scrambledAlphabet.insert(scrambledAlphabet.remove(at: i), at: j)
}
print(scrambledAlphabet)
但它不起作用。输出为:

[“A”、“B”、“C”、“D”、“H”、“F”、“G”、“E”]

问题是,一旦第一个项目被移动,下一个项目的索引就会改变。那么,解决这个问题的最佳方法是什么?我发现这很难破解。感谢您的帮助

限制是两个变量,
scrambledAlphabet
moves
,必须能够增长到任意数量

还有一个重要的注意事项,移动到索引(元组中的第二个数字)指的是旧数组,不是新创建的数组。因此,输入
[“B”、“C”、“E”、“D”、“H”、“F”、“G”、“A”]
[(7,0)、(4,7)、(3,2)]
应导致:

[“A”、“B”、“C”、“D”、“E”、“F”、“G”、“H”]

很抱歉最后一点让人困惑。

我想到了这个(我觉得有点笨拙)解决方案:

var newArray = Array(repeating: "", count: scrambledLetters.count)
for (start, end) in moves {
    newArray[end] = scrambledLetters[start]
    scrambledLetters[start] = ""
}
var scrambledLetterIndex = -1

func setScrambledLetterIndexToNextNonEmptyString() {
    scrambledLetterIndex += 1
    while scrambledLetterIndex < scrambledLetters.count - 1 && scrambledLetters[scrambledLetterIndex].isEmpty {
        scrambledLetterIndex += 1
    }
}

for i in newArray.indices {
    if newArray[i] == "" {
        setScrambledLetterIndexToNextNonEmptyString()
        newArray[i] = scrambledLetters[scrambledLetterIndex]
    }
}

scrambledLetters = newArray
然后,我慢慢地将加扰字母数组中的每个非空项复制到新数组的空位置


因为此解决方案使用空字符串,所以如果输入域包含空字符串,它将不起作用。如果是这种情况,您必须使用类似于
[String?]
的东西

一种可能的方法是使用所有索引的数组,这些索引不是任何移动的来源。然后,我们可以从一个移动或一个“其他索引”顺序填充目标:

func scramble<T>(array: [T], moves: [(Int, Int)]) -> [T] {

    // Moves sorted by increasing destination index:
    var moves = moves.sorted(by: { $0.1 < $1.1 })

    // All indices which are not the source of a move:
    let sourceIndices = Set(moves.map { $0.0 })
    var otherIndices = array.indices.filter { !sourceIndices.contains($0)}

    // Fill each position with an element of a move source,
    // or one of the "other" array elements:
    return array.indices.map {
        if let (from, to) = moves.first, $0 == to {
            moves.removeFirst()
            return array[from]
        } else {
            return array[otherIndices.removeFirst()]
        }
    }
}
例2:

print(scramble(array: [0, 1, 2, 3, 4, 5, 6, 7],
               moves: [(1, 6), (7, 2), (3, 5), (5, 3), (4, 7)]))
// [0, 2, 7, 5, 6, 3, 1, 4]

我通过将数组中的项目与其原始索引进行耦合来解决这个问题,并对移动进行排序,以便插入不会扰乱顺序。还将所有代码移动到数组扩展中:

extension Array where Element : Equatable  {

    mutating func moveItem(from fromIndex: Int, to toIndex: Int) {
        self.insert(self.remove(at: fromIndex), at: toIndex)
    }

    func performIteratedMoves(_ moves: [(Int, Int)]) -> [Element] {
        var array = self
        let enumeratedArray =  array.enumerated().map{ (index: $0, item: $1) }
        let sortedMoves = moves.sorted { $0.1 > $1.1 }

        for (i, j) in sortedMoves {
            guard let (_, item) = enumeratedArray.first(where:{ $0.index == i }), let correctIndex = array.firstIndex(where:{ $0 == item }) else { continue }
            array.moveItem(from: correctIndex, to: j)
        }
        return array
    }
}
用法:

var scrambledAlphabet = ["B", "C", "E", "D", "H", "F", "G", "A"]
var moves = [(7, 0), (4, 7), (3, 2)]
print(scrambledAlphabet.performIteratedMoves(moves))

// ["A", "B", "C", "D", "E", "F", "G", "H"]

你能展示更多的输入和输出示例吗?我想检查我的解决方案是否正确。这将不起作用,因为一旦将索引7处的对象移动到索引0,索引4处的对象将不再是H,而是E,H的索引将是5@SandeepBhandari你已经指出了问题所在,那么解决方案是什么?@Sweeper输入是变量,请随意将其扩展到完整的字母表,并执行50个预定义的移动,以查看您的解决方案是否有效。
moveItem()
来自何处?啊,对不起。把它移到一个分机里。更新了帖子。用我的第二个例子试试这个,或者更简单地用
[“A”、“B”、“C”、“D”]
移动=[(2,1)、(3,0)]
。结果应该是
[“D”、“C”、“A”、“B”]
,但是
[“D”、“A”、“C”、“B”]
我曾多次尝试通过“更正索引”来解决您的问题,但都失败了。
[“D”,“A”,“C”,“B”]
是正确的答案,“C”首先移动到“B”的位置,然后“D”移动到第一位置。请注意,这要求所有元素都是不同的:尝试
[“A”,“B”,“A”,“C”]
使用
移动=[(2,3)]
但是通过数组
[“B”,“C”,“E”,“D”,“H”,“F”,“G”,“A”]
和移动
[(7,0),(4,7),(3,2)]
这将返回[“A”,“B”,“D”,“C”,“E”,“F”,“G”,“H”]@turingtested:是的,它返回了,而且在我看来是正确的。也许我误解了任务?您希望得到什么结果?Expexted:[“A”、“B”、“C”、“D”、“E”、“F”、“G”、“H”],因为字母3(“D”)应该移动到位置2。@turingtested:对不起,我不明白。在您的预期结果中,字母“D”仍然位于第3位(指数以零为基础)。如果将“D”移动到位置2,则新数组以[“A”、“B”、“D”、…]开始@turingtested:移动
[(7,0)、(4,7)、(3,3)]
将得到预期结果(D在位置3“固定”)。
extension Array where Element : Equatable  {

    mutating func moveItem(from fromIndex: Int, to toIndex: Int) {
        self.insert(self.remove(at: fromIndex), at: toIndex)
    }

    func performIteratedMoves(_ moves: [(Int, Int)]) -> [Element] {
        var array = self
        let enumeratedArray =  array.enumerated().map{ (index: $0, item: $1) }
        let sortedMoves = moves.sorted { $0.1 > $1.1 }

        for (i, j) in sortedMoves {
            guard let (_, item) = enumeratedArray.first(where:{ $0.index == i }), let correctIndex = array.firstIndex(where:{ $0 == item }) else { continue }
            array.moveItem(from: correctIndex, to: j)
        }
        return array
    }
}
var scrambledAlphabet = ["B", "C", "E", "D", "H", "F", "G", "A"]
var moves = [(7, 0), (4, 7), (3, 2)]
print(scrambledAlphabet.performIteratedMoves(moves))

// ["A", "B", "C", "D", "E", "F", "G", "H"]