Arrays UITableView分层结构中的排序数组
我有一个customer对象数组,每个对象都有自己的ID和父ID 例如: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: 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)")
}