我有一个具有多个属性的对象数组。我需要通过这些属性将其分组。我已经写了可以做到这一点的算法。但是,我希望有一个更简洁和可重用的工具,以便我可以以其他方式对项目进行分组。
给出一个对象数组:
@objcMembers class Object: NSObject {
let name: UUID = UUID()
let value1: Int = Int(arc4random_uniform(6) + 1)
let value2: Int = Int(arc4random_uniform(6) + 1)
let value3: Int = Int(arc4random_uniform(6) + 1)
static func == (lhs: Object,rhs: Object) -> Bool {
lhs.name == rhs.name
}
}
[
Object1 {4,4,1},Object2 {1,3,2},...
Object99 {3,]
...并给出两个数据结构,Group
和Section
:
struct Group {
let title: String?
let sections: [Section]
}
struct Section {
let title: String?
let items: [Object]
}
我需要得到以下结果:
Value1: 1 // Group
Value2: 1 - Value3: 1 // Section
Object1
Object2
Object3
Value2: 1 - Value3: 2 // Section
Object1
Value2: 2 - Value3: 1 // Section
Object1
Object2
Object3
Value1: 2 // Group
Value2: 1 - Value3: 5 // Section
Object1
Value2: 4 - Value3: 1 // Section
Object1
Value2: 4 - Value3: 2 // Section
Object1
Object2
Object3
因此,对象按照它们的sections
和Value3
分组为Value2
并按升序排序。
然后,这些部分按其groups
分组为Value1
,并再次以升序排序。
我当前的算法以一种基本的命令性方法实现,我相信有很多地方有待改进。
我已经尝试过使用Swift的Dictionary.init(grouping:by:)初始化程序,然后使用Dictionary.mapValues方法对条目进行进一步分组。但是,Swift的字典没有排序,因此我必须再次进行深入的排序。
当前,我的算法如下:
// Sort the array
let value1BasedDescriptors = [
NSSortDescriptor(keyPath: \Object.value1,ascending: true),NSSortDescriptor(keyPath: \Object.value2,NSSortDescriptor(keyPath: \Object.value3,]
let sorted = (Array(objects) as NSArray).sortedArray(using: value1BasedDescriptors) as! [Object]
// Keep the previous object to find when one of the properties change
var previousObject: Object?
// Keep the group to be filled with sections
var currentGroup = [Section]()
// Keep the section to be filled with objects
var currentSection = [Object]()
// All the groups to be returned by the function
var groups = [Group]()
// Iterate over each object
for object in sorted {
// If it's a first time in a loop,set a previous object and skip
if previousObject == nil {
previousObject = object
// Append to the current section
currentSection.append(object)
continue
}
// If one of the value3 or value2 is different from the previously visited object -> Create a new section with the appropriate title
if object.value3 != previousObject?.value3 || object.value2 != previousObject?.value2 {
let section = Section(title: "Value2: \(previousObject?.value2) - Value3: \(previousObject?.value3)",items: currentSection)
// Add it to current group
currentGroup.append(section)
// Empty the section
currentSection.removeAll()
}
// If Value1 is different,group all the objects into group
if object.value1 != previousObject?.value1 {
let group = Group(title: "Value1: \(previousObject?.value1)",sections: currentGroup)
groups.append(group)
currentGroup.removeAll()
}
// Always add a visited object to a current section
currentSection.append(object)
// And mark as previous
previousObject = object
}
// since the last group & section won't be added in a loop,we have to add them manually
let section = Section(title: "Value2: \(previousObject?.value2) - Value3: \(previousObject?.value3)",items: currentSection)
currentGroup.append(section)
let group = Group(title: "Value1: \(previousObject?.value1)",sections: currentGroup)
groups.append(group)
debugPrint(groups)
它确实实现了我需要实现的目标,但是,这里有一些局限性:
- 如果要按以下顺序对对象进行分组:Value2-> Value1-> Value3?还是其他命令?然后,我必须编写相同的算法,但要更改属性
- 如果我必须多次编写相同的算法,如何将其缩短,例如使用功能性还是面向对象的方法?
完整的代码清单(复制粘贴到Playground或AppDelegate.swift
文件中):
struct Group {
let title: String?
let sections: [Section]
}
struct Section {
let title: String?
let items: [Object]
}
@objcMembers class Object: NSObject {
let name: UUID = UUID()
let value1: Int = Int(arc4random_uniform(6) + 1)
let value2: Int = Int(arc4random_uniform(6) + 1)
let value3: Int = Int(arc4random_uniform(6) + 1)
static func == (lhs: Object,rhs: Object) -> Bool {
lhs.name == rhs.name
}
}
// Create a lot of objects
var objects = Set<Object>()
for i in 0...100 {
objects.insert(Object())
}
// Sort the array
let value1BasedDescriptors = [
NSSortDescriptor(keyPath: \Object.value1,sections: currentGroup)
groups.append(group)
debugPrint(groups)