我编写了一段代码,根据字典数组创建了一个对象数组。问题是我的解决方案,它是以非常无条件的方式使用多个循环强制写的。
让我们考虑以下情况。有一个名为" Drug"
的课程class Drug {
var name:String
var dosage:[(dose:String,time:String)]
init(name:String){
self.name = name
self.dosage = []
}
}
我将数据作为字典数组获取,以下是示例:
var array = [["drugName":"Amotaks", "time":"17.00", "dose":"5"], ["drugName":"Amotaks", "time":"18.00", "dose":"5"], ["drugName":"Amotaks", "time":"18.00", "dose":"5"], ["drugName":"Amotaks", "time":"17.00", "dose":"5"], ["drugName":"Claritin", "time":"17.00", "dose":"5"], ["drugName":"Claritin", "time":"18.00", "dose":"5"]]
现在是棘手的部分,将这些数据转换为Drug对象数组的最佳方法是什么?我对我的解决方案不满意,因为它使用嵌套循环,其他辅助数组,因此效率非常低。 目的是创建对象而不重复其名称,并为每个对象提供由(剂量,时间)元组组成的剂量阵列
var DrugArray:[Drug] = []
var drugs:[String] = []
for i in array
{
if contains(drugs, i["drugName"]! as String){
continue
}
else{
drugs.append(i["drugName"]!)
DrugArray.append(Drug(name: i["drugName"]!))
}
}
for a in DrugArray{
for i in array {
if i["drugName"]! == a.name
{
a.dosage.append(dose: i["dose"]!, time: i["time"]!)
}
}}
我相信有更好的方法可以做到这一点,可能只需几行代码。我试图找出具有基本FP功能的东西,例如地图或过滤器,但我最终没有任何东西。
我的问题是:如何以优雅的方式执行上面编码的操作(可能使用更高级的功能编程)?
答案 0 :(得分:2)
首先,你应该更好地重构你的对象,因此它更容易和更易读,可能是这样的:
struct Dosage {
// Declare variables
let dose : String
let time : String
// Get dosage from drug data
init(drugData : DrugData) {
self.dose = drugData["dose"]!
self.time = drugData["time"]!
}
}
class Drug {
let name : String
var dosage = [Dosage]()
init(drugData : DrugData) {
// Assign name
self.name = drugData["dose"]!
// Append dosage
self.appendDosage(drugData)
}
func appendDosage(drugData : DrugData) {
self.dosage.append(Dosage(drugData: drugData))
}
}
请注意,我正在使用TypeAlias来掩盖字典的定义,如下所示:
typealias DrugData = [String : String]
定义药物储存:
var drugs = [String : Drug]()
现在,当您对所有定义进行整理时,您可以改进算法:
func createDrugs() {
// Your drug definitions
var array = [["drugName":"Amotaks", "time":"17.00", "dose":"5"]]
// Iterate through them
for drugDefinition in array {
// Check if there is a name, if yes, get it
if let name = drugDefinition["drugName"] {
// If drug exists, just update it, otherwise create it
if let drug = drugs[name] {
drug.appendDosage(drugDefinition)
} else {
drugs[name] = Drug(drugData: drugDefinition)
}
}
}
}
如您所见,我使用了使用药物名称作为关键词的词典。使用密钥搜索速度非常快,比遍历整个数组要快得多。我相信还有更多的改进可能性,但我认为现在适合你了:)希望它有所帮助!
答案 1 :(得分:2)
首先,让我们通过让您的药物类可打印来了解我们的工作方式:
class Drug : CustomStringConvertible {
var name:String
var dosage:[(dose:String,time:String)]
init(name:String){
self.name = name
self.dosage = []
}
var description:String {
return "\(name):\(dosage)"
}
}
然后我的第一次尝试:
let array = [["drugName":"Amotaks", "time":"17.00", "dose":"5"], ["drugName":"Amotaks", "time":"18.00", "dose":"5"], ["drugName":"Amotaks", "time":"18.00", "dose":"5"], ["drugName":"Amotaks", "time":"17.00", "dose":"5"], ["drugName":"Claritin", "time":"17.00", "dose":"5"], ["drugName":"Claritin", "time":"18.00", "dose":"5"]]
var d = [String:Drug]()
for drug in array.map ({
d -> Drug in
let drug = Drug(name:d["drugName"]!)
drug.dosage = [(dose:d["dose"]!, time:d["time"]!)]
return drug
}) {
let name = drug.name
if d[name] == nil {
d[name] = drug
} else {
d[name]!.dosage += drug.dosage
}
}
let result = Array(d.values)
print(result)
// [Claritin:[("5", "17.00"), ("5", "18.00")], Amotaks:[("5", "17.00"), ("5", "18.00"), ("5", "18.00"), ("5", "17.00")]]