使用扩展方法递归映射数组

Recursive map over array using extension method

我从 API 收到了 collection 的 LayoutElement

为简单起见,假设它包含 2 个属性 -

String[LayoutElement]

我想遍历此 collection,如果该值具有 children,则递归循环 children,返回包含 LayoutElementLayoutElement =12=]

基本上我应该得到一个 [LayoutElement],它只包含具有 String 值的元素。

因为这将在多个地方使用,我想我可以在 Array 上创建一个扩展,其中元素是 LayoutElement 但我不确定在 LayoutElement 的情况下如何最好地做到这一点=20=].

import UIKit


struct LayoutElement {
  let children: [LayoutElement]?
  let text: String?
}


let data = [
  LayoutElement(children: nil, text: "First Text Element"),
  LayoutElement(children: [
    LayoutElement(children: nil, text: "Second Text Element"),
    LayoutElement(children: nil, text: "Third Text Element"),
    LayoutElement(children: [
      LayoutElement(children: nil, text: "Fourth Text Element"),
    ], text: nil)
  ], text: nil),
]



extension Array where Element == LayoutElement {
  var asLayout: [LayoutElement] {
    return map { element in
      if let children = element.children {
        // ???
      } else {
        return element
      }
    }
  }
}

let output = data.asLayout

print(output)

您应该能够通过在返回结果之前在本地数组中捕获您的集合来实现这一点

extension Array where Element == LayoutElement {
  var asLayout: [LayoutElement] {
    var flatten: [LayoutElement] = []
    forEach { item in
      if let children = item.children {
        children.asLayout.forEach { child in
          flatten.append(child)
        }
      } else {
        flatten.append(item)
      }
    }

    return flatten
  }
}

有一个临时数组来收集所有结果:

extension Array where Element == LayoutElement {
    var asLayout: [LayoutElement] {
        var result = [LayoutElement]()
        forEach {
            if let children = [=10=].children {
                result.append(contentsOf: children.asLayout)
            } else if [=10=].text != nil {
                result.append([=10=])
            }
        }
        return result
    }
}

您不知道该怎么做,因为您选择了错误的高阶函数。您应该使用 flatMap,而不是 map

map 将每个数组元素转换为另一个元素,但 flatMap 可以将每个元素转换为 多个 其他元素。当结果数组的大小与起始数组的大小不同时,您应该使用 flatMap ,这里就是这种情况。 data 有 2 个元素,而 output 应该有 4 个元素。 map永远不能增加元素的数量。

  var asLayout: [LayoutElement] {
    return flatMap { element -> [LayoutElement] in
      // for each element, we return the array of elements into which we want to transform it
      if let children = element.children {
        return children.asLayout
      } else {
        return [element] // we don't want to transform it, so we return an array containing only "element"
      }
    }
  }

返回 children.asLayout 就可以了。

或一行:

var asLayout: [LayoutElement] {
    flatMap { [=11=].children?.asLayout ?? [[=11=]] }
}