使用 swift 内置分区来管理数组中的元素

Using swift built in partition to manage elements in an array

iOS 14, Swift 5.x

我从 2018 年开始观看这个优秀的 WWDC

https://developer.apple.com/videos/play/wwdc2018/223/

我写了一个形状编辑器...并且一直在尝试使用分区,正如 Dave 在视频中所说的那样。我让前三个工作,但最后一个我不得不使用循环 - 我无法终生弄清楚如何让它与分区一起工作。

有人能看到我该怎么做吗?

第一种方法将所选对象移动到列表末尾,效果很好。

func bringToFrontEA() {
let subset = objects.partition(by: { [=11=].selected })
let selected = objects[subset...]
let unselected = objects[..<subset]
let reordered = unselected + selected
objects = Array(reordered)
}

第二种方法将选中的对象移动到列表的前面。完美运行。

func sendToBackEA() {
let subset = objects.partition(by: { ![=12=].selected })
let selected = objects[subset...]
let unselected = objects[..<subset]
let reordered = unselected + selected
objects = Array(reordered)
}

第三种方法仅将元素移回列表中的一个元素。完美运行。

func sendBackEA() {
if let i = objects.firstIndex(where: { [=13=].selected }) {
  if i == 0 { return }
  let predecessor = i - 1
  let shapes = objects[predecessor...].partition(by: { ![=13=].selected })
  let slice = objects[predecessor...]
  let row = objects[..<predecessor]
  
  let selected = Array(slice[..<shapes])
  let unselected = Array(slice[shapes...])
  
  objects = row + selected + unselected
}
}

最后一种方法在列表中向前移动元素,效果很好...但与其他方法不同,它不会像 WWDC 视频中描述的那样缩放。

func bringForwardEA() {
let indexes = objects.enumerated().filter { [=14=].element.selected == true }.map{[=14=].offset}
for i in indexes {
    if objects[i+1].unused {
      return
    }
    objects.swapAt(i+1, i)
  }
}

Objects 是一个形状数组,带有一个 属性 指示它是否被选中。我想像在前三个方法中那样使用分区来交换最后一个方法中的循环。它需要适用于一个或多个选定的形状。

看WWDC视频,好像你说的sendBackEA是WWDC说的bringForward,你说的bringForwardEA是WWDC说的[=14] =].

就像你将第一个选中的元素向前移动一个索引(索引递减)在sendBackEA,然后移动所有其他选定元素立即在第一个选定元素之后。 bringForwardEA 应该相反:将 last 选定元素 向后 移动一个索引(索引增加),然后移动所有其他选定元素立即 最后一个选定元素之前。 (请参阅视频中的大约 19:10)

您似乎对尝试将所有选定索引的索引增加 1 感到困惑。这显然不能用一般的分区来完成。

另请注意,partition(by:)已经修改了集合,您不需要获取每个分区,然后重新组合。

你的4个方法可以这样写:

func bringToFrontEA() {
    objects.partition(by: { [=10=].selected })
}

func sendToBackEA() {
    objects.partition(by: { ![=10=].selected })
}

func sendBackEA() {
    if let i = objects.indices.first(where: { objects[[=10=]].selected }) {
      if i == 0 { return }
      let predecessor = i - 1
      objects[predecessor...].partition(by: { ![=10=].selected })
    }
}

func bringForwardEA() {
    if let i = objects.indices.last(where: { objects[[=10=]].selected }) {
        if i == objects.indices.last { return }
        let successor = i + 1
        objects[...successor].partition(by: { ![=10=].selected })
    }
}

注意 sendBackEAbringForwardEA 之间的对称性。