【问题标题】:Iterate an array of dictionaries to get highest gpa迭代字典数组以获得最高 gpa
【发布时间】:2019-01-23 00:38:57
【问题描述】:

家庭作业问题。 我需要遍历一系列字典以获得最高 gpa 并打印学生的名字和姓氏。我在访问字典条目的 gpa 字段时遇到问题。

// Task 6
var highestGPA = 0.0
var students : [[String:Any]] =
    [["firstName": "John", "lastName": "Wilson", "gpa": 2.4],
     ["firstName": "Nancy", "lastName": "Smith", "gpa": 3.5],
     ["firstName": "Michael", "lastName": "Liu", "gpa": 3.1]]

for index in students   {
    if let val = (_,_,"gpa":key) {
        highestGPA = val
    }
}

预期的结果是它遍历字典数组并获得最高的 gpa。 实际结果是编译错误“二元运算符 '>' 不能应用于 (,,String) 和 Double 类型的操作数。 所以它似乎得到了字符串“gpa”而不是gpa的值

编辑:我还尝试了以下代码来获取“gpa”字段中的值并转换为双精度值。

for index in students   {
    myGPA = Double(index["gpa"])
    if myGPA > highestGPA   {
        highestGPA = myGPA
    }        
}

我得到编译错误:错误:无法使用类型为“(任何?)”的参数列表调用类型“Double”的初始化程序 我的GPA = Double(index["gpa"])

【问题讨论】:

  • 应该创建一些结构来存储人员,而不是数组。这样,您可以拥有强类型成员(gpa 将是一个 Double,不需要常量 as! Double 强制转换)并且不必使用字符串来查找成员(如果您打错了怎么办?)
  • if let myGPA = index["gpa"] as? Double {

标签: arrays swift dictionary


【解决方案1】:

您可以使用Array函数max来确定GPA最高的学生。

let student = students.max { $0["gpa"] as? Double ?? 0 < $1["gpa"] as? Double ?? 0 }

print(student?["firstName"]) // Nancy
print(student?["gpa"]) // 3.5

【讨论】:

  • 哎呀,应该先在操场上进行测试。谢谢!
【解决方案2】:

由于您已将字典中的值标记为Any,因此在使用它时必须将其向下转换为as? Double。下面的代码解决了你的问题。

var highestGpa = 0.0
var highestPerformingStudent = students[0]
for student in students {
    if let gpa = student["gpa"] as? Double {
        if (gpa > highestGpa) {
            highestGpa = gpa
            highestPerformingStudent = student
        }
    }
}

print(highestPerformingStudent)
// prints ["firstName": "Nancy", "lastName": "Smith", "gpa": 3.5]

【讨论】:

  • 你应该尽可能避免强制转换。如果字典不包含 gpa 键,则会导致整个应用崩溃。
  • +1 @EmilioPelaez 所说的,强制展开很少是一个好建议,请不要向初学者推荐这样的东西。
  • 这是班主任建议我们做的。
  • @RossSatchell 很高兴听到 - 请注意其他人提到的强制向下转换。我编辑了答案以展示最佳实践。
【解决方案3】:

正如@Alexander 在 cmets 中建议的那样,您最好定义一个 struct 来保存您的学生姓名和 gpa 数据。然后您将拥有强类型成员,而不必将Any 转换为StringDouble。结构自动提供一个初始化器,它接受每个成员。这可以防止您在初始化 Student 数据数组时打错字。

创建struct CustomStringConvertible 并实现var description 可以很好地格式化struct 的输出。

然后您可以使用max(by:) 通过传递定义如何比较两条Student 记录的闭包来查找Student 和最大gpa

struct Student: CustomStringConvertible {
    var firstName: String
    var lastName: String
    var gpa: Double

    var description: String { return "\(firstName) \(lastName) (\(gpa))" }
}

let students: [Student] = [
    Student(firstName: "John", lastName: "Wilson", gpa: 2.4),
    Student(firstName: "Nancy", lastName: "Smith", gpa: 3.5),
    Student(firstName: "Michael", lastName: "Liu", gpa: 3.1)
]

if let student = students.max(by: { $0.gpa < $1.gpa }) {
    // Print the student information
    print(student)

    // Print the student's name
    print("\(student.firstName) \(student.lastName)")

    // Print the highest gpa
    print(student.gpa)
}

输出:

Nancy Smith (3.5)
Nancy Smith
3.5

另一种初始化Student数据的方法:

正如@LeoDabus 建议的那样,您可以使用元组数组和map() 来初始化您的students 数组,如下所示:

let students = [
    ("John", "Wilson", 2.4),
    ("Nancy", "Smith", 3.5),
    ("Michael", "Liu", 3.1)
].map(Student.init)

这具有消除视觉混乱和节省输入的优点,但代价是不明确显示正在初始化的字段。

【讨论】:

    猜你喜欢
    • 2022-01-01
    • 2018-09-04
    • 2014-09-12
    • 1970-01-01
    • 2014-04-10
    • 1970-01-01
    • 1970-01-01
    • 2014-07-22
    • 2016-09-24
    相关资源
    最近更新 更多