首页 > 解决方案 > 使用 swift 内置分区来管理数组中的元素

问题描述

iOS 14、斯威夫特 5.x

我从 2018 年开始观看了这个出色的 WWDC

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

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

有人可以看到我该怎么做吗?

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

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

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

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

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

func sendBackEA() {
if let i = objects.firstIndex(where: { $0.selected }) {
  if i == 0 { return }
  let predecessor = i - 1
  let shapes = objects[predecessor...].partition(by: { !$0.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 { $0.element.selected == true }.map{$0.offset}
for i in indexes {
    if objects[i+1].unused {
      return
    }
    objects.swapAt(i+1, i)
  }
}

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

标签: swiftpartition

解决方案


看 WWDC 视频,看来你叫sendBackEA什么就是 WWDC 叫bringForward什么,你叫bringForwardEA什么就是 WWDC 叫什么sendBack

就像您如何将第一个选定元素向前移动一个索引(索引减小) in sendBackEA,然后将所有其他选定元素移动到该第一个选定元素之后bringForwardEA应该做相反的事情:将最后一个选定元素向后移动一个索引(索引增加),然后将所有其他选定元素移动到最后一个选定元素之前。(见视频中大约 19:10)

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

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

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

func bringToFrontEA() {
    objects.partition(by: { $0.selected })
}

func sendToBackEA() {
    objects.partition(by: { !$0.selected })
}

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

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

sendBackEA注意和之间的对称性bringForwardEA


推荐阅读