将两个数组映射为对象数组的一些实践 - Swift

970 阅读2分钟

假设有一个需求,需要根据两个数组的内容生成一个对象数组。比如下面的代码:

let ages = [21, 20, 23, 24]
let names = ["张三", "李四", "王二", "赵六"]

struct Student {
    var name: String
    var age: Int
}

现有 agesnames 两个数组,我们需要根据这两个数组的内容生成一个包含 Student 对象的数组。

map ?

如果是一个数组把它映射成对象数组的话,用 map 是最合适的,比如下面的代码:

struct Student {
    var name: String
}

let names = ["张三", "李四", "王二", "赵六"]
let stus = names.map { Student(name: $0) }

但我们需要将 ages 和 names 的值都添加到 Student 对象中,而 map 函数并没有提供 index 的参数,所以 map 无法实现上述的需求。

zip ?

因为我们需要同时用到两个数组同一位置的元素,所以也可能回想到它。比如下面的代码:

let stuSeq = zip(ages, names)
var stus = [Student]()
for (age, name) in stuSeq {
    stus.append(Student(name: name, age: age))
}

虽然上面的代码也可以实现需求,但是代码不够 Swift,Swift 官方是推荐我们更多的使用高阶函数,尽可能的少用 for-in 等循环语句,原因是高阶函数更易读、易维护。

map + zip ✔️

通过上面的尝试可以发现,map 和 zip 单独使用要么不能实现需求,要么代码不够优雅,那么它们组合起来使用呢?

下面就是终极版本:

// 先构造 Zip2Sequence
let stuSeq = zip(ages, names)
// 再去映射
let stus = stuSeq.map { (age, name) -> Student in
    return Student(name: name, age: age)
}

这样我们即实现了需求,也因为使用了 map 函数而可以将 stus 声明为 let(zip 因为要添加元素所以不能将 stus 声明为 let),从而使代码易读、健壮。

希望读完这篇文章,大家能有一些收获。对于这种需求小伙伴们有没有更好的解决方案呢?欢迎在评论区留言。