Arrays 在Swift中对数组进行分组和排序
假设我有以下代码:Arrays 在Swift中对数组进行分组和排序,arrays,swift,sorting,Arrays,Swift,Sorting,假设我有以下代码: class Stat { var statEvents : [StatEvents] = [] } struct StatEvents { var name: String var date: String var hours: Int } var currentStat = Stat() currentStat.statEvents = [ StatEvents(name: "lunch", date: "01-01-2015", hou
class Stat {
var statEvents : [StatEvents] = []
}
struct StatEvents {
var name: String
var date: String
var hours: Int
}
var currentStat = Stat()
currentStat.statEvents = [
StatEvents(name: "lunch", date: "01-01-2015", hours: 1),
StatEvents(name: "dinner", date: "02-01-2015", hours: 2),
StatEvents(name: "dinner", date: "03-01-2015", hours: 3),
StatEvents(name: "lunch", date: "04-01-2015", hours: 4),
StatEvents(name: "dinner", date: "05-01-2015", hours: 5),
StatEvents(name: "breakfast", date: "06-01-2015", hours: 6),
StatEvents(name: "lunch", date: "07-01-2015", hours: 7),
StatEvents(name: "breakfast", date: "08-01-2015", hours: 8)
]
我想知道是否有一种方法可以获得具有如下输出的数组:
- [0]
- name : "lunch"
- date
- [0] : "01-01-2015"
- [1] : "04-01-2015"
- [2] : "07-01-2015"
- hours
- [0] : 1
- [1] : 4
- [2] : 7
- [1]
- name : "dinner"
- date
- [0] : "02-01-2015"
- [1] : "03-01-2015"
- [2] : "05-01-2015"
- hours
- [0] : 2
- [1] : 3
- [2] : 5
- [2]
- name : "breakfast"
- date
- [0] : "06-01-2015"
- [1] : "08-01-2015"
- hours
- [0] : 6
- [1] : 8
如您所见,最终数组应该按“name”子体分组。
@oisdk您能检查一下吗???最终结果是[[String:AnyObject]]类型,或者您创建了一个新的structtype来保存这些值,结果是[String:NewStructType]类型:
struct NewStructType
{
var dates: [String]?
var hours: [Int]?
}
因此,您必须对此做出决定,然后必须编写自己的函数来对StateEvents对象进行排序和分组。也许您可以优化它的性能,但下面是如何实现第二个版本(使用NewStructType)的第一个想法:
这似乎有些过分,但我想到的是解决办法
extension Array {
/**
Indicates whether there are any elements in self that satisfy the predicate.
If no predicate is supplied, indicates whether there are any elements in self.
*/
func any(predicate: T -> Bool = { t in true }) -> Bool {
for element in self {
if predicate(element) {
return true
}
}
return false
}
/**
Takes an equality comparer and returns a new array containing all the distinct elements.
*/
func distinct(comparer: (T, T) -> Bool) -> [T] {
var result = [T]()
for t in self {
// if there are no elements in the result set equal to this element, add it
if !result.any(predicate: { comparer($0, t) }) {
result.append(t)
}
}
return result
}
}
let result = currentStat.statEvents
.map({ $0.name })
.distinct(==)
.sorted(>)
.map({ name in currentStat.statEvents.filter({ $0.name == name }) })
现在您有了一个列表列表,其中第一个列表包含晚餐类型的所有状态事件,下一个列表包含午餐类型的事件,等等
明显的缺点是,这可能比其他解决方案性能差。很好的一点是,您不必依赖并行阵列来获取与特定日期相关联的小时数。我的目标:
extension StatEvents : Comparable {}
func < (lhs:StatEvents, rhs:StatEvents) -> Bool {
if lhs.name != rhs.name {
return lhs.name > rhs.name
} else if lhs.date != rhs.date {
return lhs.date < rhs.date
} else {
return lhs.hours < rhs.hours
}
}
func == (lhs:StatEvents, rhs:StatEvents) -> Bool {
return lhs.name == rhs.name
&& lhs.date == rhs.date
&& lhs.hours == rhs.hours
}
struct ResultRow {
var name: String
var dates: [String]
var hours: [Int]
}
var result : [ResultRow] = []
let sorted = currentStat.statEvents.sort()
for event in sorted {
if result.last?.name != event.name {
result.append(ResultRow(name: event.name, dates: [], hours: []))
}
result[result.endIndex - 1].dates.append(event.date)
result[result.endIndex - 1].hours.append(event.hours)
}
印刷品:
p.ResultRow(name: "lunch", dates: ["01-01-2015", "04-01-2015", "07-01-2015"], hours: [1, 4, 7])
p.ResultRow(name: "dinner", dates: ["02-01-2015", "03-01-2015", "05-01-2015"], hours: [2, 3, 5])
p.ResultRow(name: "breakfast", dates: ["06-01-2015", "08-01-2015"], hours: [6, 8])
已经有了一些答案,但这很有趣。我的答案没有在Swift中使用很多高阶函数,但它完成了工作:
// Get the list of unique event names
var eventNames = [String]()
for event in currentStat.statEvents {
if !eventNames.contains(event.name) {
eventNames.append(event.name)
}
}
// The type of the result
struct ResultType {
var name : String
var date : [String]
var hours : [Int]
}
var result = [ResultType]()
for name in eventNames {
let matchingEvents = currentStat.statEvents.filter { $0.name == name }
let dates = matchingEvents.map { $0.date }
let hours = matchingEvents.map { $0.hours }
result.append(ResultType(name: name, date: dates, hours: hours))
}
无需在结构定义中选择日期和小时。它还可以有一个初始值设定项,该初始值设定项采用日期[String]和小时[Int]。此外,如果这是一次性使用,则类型可以是“[String:(dates:[String],hours:[Int])]”。如果您将此值传递给本地上下文或类之外的调用方,那么拥有该结构将是一件好事。谢谢您的帮助!
p.ResultRow(name: "lunch", dates: ["01-01-2015", "04-01-2015", "07-01-2015"], hours: [1, 4, 7])
p.ResultRow(name: "dinner", dates: ["02-01-2015", "03-01-2015", "05-01-2015"], hours: [2, 3, 5])
p.ResultRow(name: "breakfast", dates: ["06-01-2015", "08-01-2015"], hours: [6, 8])
// Get the list of unique event names
var eventNames = [String]()
for event in currentStat.statEvents {
if !eventNames.contains(event.name) {
eventNames.append(event.name)
}
}
// The type of the result
struct ResultType {
var name : String
var date : [String]
var hours : [Int]
}
var result = [ResultType]()
for name in eventNames {
let matchingEvents = currentStat.statEvents.filter { $0.name == name }
let dates = matchingEvents.map { $0.date }
let hours = matchingEvents.map { $0.hours }
result.append(ResultType(name: name, date: dates, hours: hours))
}