flatMap方法的实际应用— Swift 3

这一次,我们将讨论flatMap方法。

但是首先让我们考虑一下上下文。

假设我们有一个数组数组:

 var arrayOfArrays = [ [1, 1], [2, 2], [3, 3] ] 

将其内容乘以2是一个挑战,其结果应如下所示:

  // [[2,2],[4,4],[6,6]] 

解决此难题的一种方法可能是两次使用map Array的方法,如下所示:

  //首先迭代数组的数组 
arrayOfArrays。 映射 {数组在

//和第二次迭代
//当前数组
返回数组。 映射 {中的整数
//将其内容乘以2
返回整数* 2
}
  } // [[2,2],[4,4],[6,6]] 

好的,接下来是一个新的挑战,将乘法数组转换为仅一个数组,如下所示:

  // [2,2,4,4,6,6] 

幸运的是Array的结构为此目的有一个称为joined ,让我们使用它:

  var multipliedByTwo = arrayOfArrays。  映射 {数组在 
返回数组。 映射 {中的整数
返回整数* 2
}
}
  var flattened = Array(multipliedByTwo。join()) 
print(flattened)//输出:[2,2,4,4,6,6]

但是实际上Array的结构已经有一个方法可以同时完成这两项操作,即映射和展平,是的,这是flatMap

  var arrayOfArrays = [[1,1],[2,2],[3,3]] 
  var flattenedArray = arrayOfArrays。  flatMap {数组在 
返回数组。 映射 {中的整数
返回整数* 2
}
}
  print(flattenedArray)//输出: [2,2,4,4,6,6] 

让我们来看另一个例子。

实际上,如果我们迭代数组,则flatMapmap行为类似:

 让数字: [整数] = [1、2、3] 
 让numbersMap =数字。  地图 {return $ 0} 
print(numbersMap)// [1、2、3]
 让numbersFlatMap =数字。  flatMap {返回$ 0} 
print(numbersFlatMap)// [1、2、3]

但是,如果我们有一系列可选选项,那就会有很大的不同:

 让数字: [Int?] = [1, nil ,3] 
 让numbersMap =数字。  地图 {return $ 0} 
print(numbersMap)// [可选(1),无,可选(3)]
 让numbersFlatMap =数字。  flatMap {返回$ 0} 
print(numbersFlatMap)// [1,3]

虽然map方法实际上不会更改numbersMap数组结果的任何内容,但是flatMap有两件事:首先从Int?转换项目的类型Int? 转换为Int ,然后删除转换后的转换numbersFlatMap,上的nilnumbersFlatMap,非常简洁。

现在让我们结束在实际世界中flatMap的实际使用:

假设我们有一个名为getJSON的方法,该方法基于url将为我们提供来自服务器的字典数组:

 让url =“ https://jsonplaceholder.typicode.com/users” 
  getJSON(from:url){(dictionaries: [Dictionary ]? )在 
打印(词典)
//输出:
// 可选([
// [[“ name”:Leanne Graham,“ id”:1],
// [..],
//])
}

因此,我们创建了一个User结构来存储此数据:

  struct 用户 { 
  let id:整数 
命名:字符串
let用户名:字符串
  在里面?  (字典:Dictionary ){ 
守护
让id = dictionary [“ id”]为? 诠释
让name = dictionary [“名称”]为? 串,
让username = dictionary [“ username”]为? 串
其他 {
返回零
}
  self.id = id 
self.name =名称
self.username =用户名
}
  } 

User类型array中转换数据的经典方法可能是这样的:

  getJSON(from:url){(dictionaries: [Dictionary ]? )在 
如果让字典=字典{
var users = [User]()
 用于字典中的字典{ 
让用户=用户(字典:词典)

如果让用户=用户{
users.append(用户)
}
}
 打印(用户) 
// [ User(id:1,name:“ Leanne Graham”,username:“ Bret”),..]
  } 
}

请记住,在创建通过dictionary的新User ,由于我们将init声明为可失败的初始化,因此它有可能无法初始化并返回nil

  struct用户{ 
//一些代码
  //失败的初始化 
在里面? (字典:Dictionary ){
//一些代码
}
}

这就是为什么我们在添加到users数组之前验证用户不是nil的原因。

但是还有另一种使用flatMap迭代字典的方法

  getJSON(from:url){(dictionaries: [Dictionary ]? )在 
如果让字典=字典{
var users = [User]()
  //接受字典并返回用户? 
让闭包:(Dictionary )->用户?
  //初始化闭包 
闭包= {
返回用户(字典:字典)
}
  用户 =字典。  flatMap (关闭) 
 打印(用户) 
// [ User(id:1,name:“ Leanne Graham”,username:“ Bret”),..]
  } 
}

因此, flatMap将做三件事:

  1. 当然,迭代dictionaries数组以转换User类型的数组
  2. 如果创建的User没有任何问题,则flatMap可以从User?转换User? User键入每个元素。
  3. 它过滤nil值,因为失败的初始化程序( init?)可能返回nil

flatMap完成后,我们将获得[User]数组。

最后,我们可以进一步减少代码,如下所示:

  getJSON(from:url){(dictionaries: [Dictionary ]? )在 
如果让字典=字典{
var users = [User]()
  用户 =字典。  flatMapUser.init
 打印(用户) 
// [ User(id:1,name:“ Leanne Graham”,username:“ Bret”),..]
  } 
}

如果看到在我们使用闭包的代码,则其类型为:

 让闭包: (Dictionary )->用户? 
  //代码 
 用户= dictionaries.flatMap( 闭包

需要使用Dictionary 作为参数并返回User?

而且,如果您看到User结构的初始化函数:

  在里面?  (字典:Dictionary ){ 
//一些代码
}

期望使用Dictionary 作为参数 当然是它的init? 函数调用将返回一个 User?

这就是为什么我们将User.init (这是User结构的init函数)传递给flatMap

  用户 =字典。  flatMapUser.init

我们看到了许多使用flatMap方法的示例,但要记住的一些重要要点是:

  • 当使用数组数组时,应用flatMap会做两件事,映射和展平。
  • 当使用可选类型的数组时, flatMap将映射,将可选类型转换为非可选类型,并删除nil值。

就是这样,希望对您有所帮助。

感谢您阅读我!