Arrays UITableView分层结构中的排序数组

Arrays UITableView分层结构中的排序数组,arrays,swift,sorting,Arrays,Swift,Sorting,我有一个customer对象数组,每个对象都有自己的ID和父ID 例如: [ Customer(id: 1, parentId: nil), Customer(id: 2, parentId: 3), Customer(id: 3, parentId: 1), Customer(id: 4, parentId: 1) ] 我的目标是重新排列它们,使所有的子对象都位于数组中父对象的下方,如下所示(或类似内容): 然后,我将使用它缩进表视图单元格,以显示客户的层次结

我有一个customer对象数组,每个对象都有自己的ID和父ID

例如:

[
    Customer(id: 1, parentId: nil),
    Customer(id: 2, parentId: 3),
    Customer(id: 3, parentId: 1),
    Customer(id: 4, parentId: 1)
]
我的目标是重新排列它们,使所有的子对象都位于数组中父对象的下方,如下所示(或类似内容):

然后,我将使用它缩进表视图单元格,以显示客户的层次结构


我见过像和这样的问题,但我不知道如何将其应用于Swift。如何对数组进行排序?

您可以使用递归实现这种嵌套层次排序,例如

/* recursive sorting */
func foo(inout remainingCustomers: [Customer], inout _ sortedCustomers: [Customer], _ parentId: Int? = nil) {
    let children = remainingCustomers.filter { $0.parentId == parentId }
    for child in children {
        sortedCustomers.append(child)
        foo(&remainingCustomers, &sortedCustomers, child.id)
    }
    remainingCustomers = remainingCustomers.filter { $0.parentId != parentId }
}
使用您的客户数组(例如
customer
)和空数组(例如
sortedCustomers
)调用,其中后者是将排序的客户追加到的结果数组

/* example setup */
struct Customer {
    let id: Int
    let parentId: Int?
}

var customers : [Customer] = [
    Customer(id: 13, parentId: 2),
    Customer(id: 14, parentId: 5),
    Customer(id: 1, parentId: nil),
    Customer(id: 2, parentId: 3),
    Customer(id: 7, parentId: 2),
    Customer(id: 3, parentId: 1),
    Customer(id: 4, parentId: 14),
    Customer(id: 5, parentId: nil),
    Customer(id: 6, parentId: 1)]

/* example usage */
var sortedCustomers : [Customer] = []
foo(&customers, &sortedCustomers)

sortedCustomers.forEach { print($0) }
/* Customer(id: 1, parentId: nil)
   Customer(id: 3, parentId: Optional(1))
   Customer(id: 2, parentId: Optional(3))
   Customer(id: 13, parentId: Optional(2))
   Customer(id: 7, parentId: Optional(2))
   Customer(id: 6, parentId: Optional(1))
   Customer(id: 5, parentId: nil)
   Customer(id: 14, parentId: Optional(5))
   Customer(id: 4, parentId: Optional(14))  */
请注意,随着
客户
阵列规模的增长,上述w.r.t.性能(例如
foo
中的双重过滤)并不是非常优化。由于排序的上下文是一个将显示给用户的数组,因此我假设您不会将上述内容用于大型数组。如果这成为一个问题,那么只有从这个算法的成熟优化开始


为了便于查看结果,您可以在递归中包含
depth
属性,例如,如下所示,使用与递归深度成比例的填充打印子项(同时附加到
sortedCustomers
):

/* recursive sorting */
func foo(inout remainingCustomers: [Customer], inout _ sortedCustomers: [Customer], _ parentId: Int? = nil, _ depth: Int = 0) {
    let children = remainingCustomers.filter { $0.parentId == parentId }
    for child in children {
        sortedCustomers.append(child)
        let padding = String(count: 4*depth, repeatedValue: (" " as Character))
        print(padding + "\(child)")
        foo(&remainingCustomers, &sortedCustomers, child.id, depth+1)
    }
    remainingCustomers = remainingCustomers.filter { $0.parentId != parentId }
}

/* example usage */
var sortedCustomers : [Customer] = []
foo(&customers, &sortedCustomers)
/*
Customer(id: 1, parentId: nil)
    Customer(id: 3, parentId: Optional(1))
        Customer(id: 2, parentId: Optional(3))
            Customer(id: 13, parentId: Optional(2))
            Customer(id: 7, parentId: Optional(2))
    Customer(id: 6, parentId: Optional(1))
Customer(id: 5, parentId: nil)
    Customer(id: 14, parentId: Optional(5))
        Customer(id: 4, parentId: Optional(14))     */

因为您需要缩进级别和顺序,所以应该提前计划并准备缩进级别以及排序

您可以通过一种相对简单的方法来实现这一点:首先向父级添加依赖项(或者如果您无法控制
Customer
类,则在父级之外构建依赖项),然后首先遍历树深度,并按拓扑顺序存储结果

下面是一个如何做到这一点的示例。它使用此
客户
类:

public class Customer : CustomStringConvertible {
    public var Dependents = [Customer]()
    public let Id : Int
    public let Parent : Int?
    public init(_ id:Int, _ parent:Int?) {
        Id = id
        Parent = parent
    }
    public var description: String {
        return "Customer Id=\(Id) Parent=\(Parent)"
    }
}
请注意,每个
客户
都有一个
依赖项数组
,以及自己的ID和其父项的可选ID

排序之前,您需要向每个客户添加依赖项。您可以通过两次调用
forEach

let cust = [ Customer(2, 3), Customer(3, 1), Customer(1, nil), Customer(4, 1), Customer(5, 3)]
var byId = [Int:Customer]()
// Add each customer to dictionary by ID
cust.forEach { byId[$0.Id] = $0 }
// Go throug customers again, this time adding them to their parents
cust.forEach { c in
    if let parentId = c.Parent {
        byId[parentId]?.Dependents.append(c)
    }
}
有了
byId
,您可以准备数组以获得结果,并开始排序。我将使用
(Customer,Int)
的元组表示客户及其缩进级别:

var sorted = [(Customer,Int)]()
// Recursive local function for adding dependents to the result
func store(customer:Customer, _ level:Int) {
    sorted.append((customer, level))
    customer.Dependents.forEach { store($0, level+1) }
}
// Call the recursive function for each top-level customer:
for c in cust.filter({ $0.Parent == nil }) {
    store(c, 0)
}
就这样-现在我们可以用缩进打印结果,如下所示:

for (customer, level) in sorted {
    let indent = String(count:level, repeatedValue:Character(" "))
    print("\(indent) \(customer)")
}

你确实希望有多层次的父母,对吗?换句话说,它不仅仅是一个两级父子层次结构,它还可以有更多的层?@dasblinkenlight是的,可以有两个以上的层。我需要在缩进单元格时解释这一点,但这是下一步。@brimstone很乐意帮忙!有了大量的客户,这在性能方面又能维持多久?@brimstone假设便携式设备上的“很多”意味着“一千或两个”,这应该不会很糟糕。如果你有一百万的客户,你很可能是在一个有强大CPU的服务器上做这件事,所以这也不会太糟糕。我可以看到,这对于一亿客户来说是一个问题,因为在这种情况下,您可能希望利用多核系统上可用的一些并行性。
for (customer, level) in sorted {
    let indent = String(count:level, repeatedValue:Character(" "))
    print("\(indent) \(customer)")
}