【发布时间】:2016-04-11 06:54:33
【问题描述】:
考虑数组[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].
【问题讨论】:
考虑数组[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].
【问题讨论】:
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
}
这会将 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
}
这里需要vararr,因为如果不将输入参数指定为in-out,就无法改变它。然而,在我们的例子中,我们得到了一个没有副作用的纯函数,在我看来,这更容易推理。
然后你可以这样称呼它:
let arr = [1,2,3,4]
rearrange(arr, fromIndex: 2, toIndex: 0) //[3,1,2,4]
【讨论】:
所有的好答案!这是一个更完整的 Swift 5 解决方案,它考虑到了性能并为基准和 GIF 爱好者提供了奖励。 ✌️
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)
}
}
【讨论】:
if oldIndex == newIndex { return } 行。编辑:好吧,我又想了。如果你保留这条线,abs(newIndex - oldIndex) 不会被不必要地计算。
swapAt,而不仅仅是在它们并排时使用。对于这些情况,使用insert/remove 是更好的解决方案吗?
[A, B, C, D]。将索引3 处的项目移动到0 会得到[D, A, B, C]。将索引 3 处的项目交换为 0 会得到 [D, B, C, A]。
swapAt 交换了两个元素。这相当于同时删除元素 A 和 B,然后在 B 之前的位置插入 A,在交换之前 A 的位置插入 B。 [w, A, x, y, B, z].swapAt(1, 4) 将导致 [w, B, x, y, A, z],A 和 B 的位置交换,其他元素(w、x、y 和 z)的位置不变。
编辑/更新: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]
【讨论】:
来自 Leo 的好建议。
对于 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)
【讨论】:
var arr = ["one", "two", "three", "four", "five"]
// Swap elements at index: 2 and 3
print(arr)
arr.swapAt(2, 3)
print(arr)
【讨论】:
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)
}
}
【讨论】:
我们可以使用 swap 方法来交换数组中的元素:
var arr = ["one", "two", "three", "four", "five"]
// Swap elements at index: 2 and 3
print(arr)
swap(&arr[2], &arr[3])
print(arr)
【讨论】:
let element = arr.removeAtIndex(2) & arr.append(element)
@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 中没有数组的移动功能。您可以通过从那里删除对象来获取索引中的对象,然后使用“插入”将其放入您最喜欢的索引中
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 中所有项目的方法。我不确定如何将扩展限制为更通用的形式,而不是限制元素而不是整数,同时保持构造 IndexSets 的能力,因为我对 Swift 协议的了解并不广泛。
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)
}
}
}
【讨论】:
self.remove() 将更改数组,因此toIndex 不一定会指向与调用rearrange() 之前相同的项目。取决于fromIndex 是大于还是小于toIndex。
使用 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))
}
}
【讨论】:
Leo Dabus 的解决方案很棒,但是如果不满足条件,使用前置条件(从 != 到 && 索引.contains(从 != 到 && 索引.contains(to),“无效索引”)将使应用程序崩溃。我将其更改为保护和 if 语句 - 如果由于某种原因不满足条件,则不会发生任何事情并且应用程序会继续运行。我认为我们应该避免进行可能导致应用程序崩溃的扩展。如果您希望可以使重新排列功能返回a 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]
【讨论】:
array.swap(...))
这个解决方案怎么样? 要更改的元素和要更改的元素已更改。
// 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"]
【讨论】:
firstindex +1) 您假设 newIndex