Swift map filter reduce 使用指南
转载:https://useyourloaf.com/blog/swift-guide-to-map-filter-reduce/
Using map
, filter
or reduce
to operate on Swift collection types such as Array
or Dictionary
is something that can take getting used to. Unless you have experience with functional languages your instinct may be to reach for the more familiar for-in loop. With that in mind here is my guide to using map, filter, reduce (and flatMap).
Map
Use map
to loop over a collection and apply the same operation to each element in the collection. The map
function returns an array containing the results of applying a mapping or transform function to each item:
We could use a for-in loop to compute the squares of each item in an array:
let values = [2.0,4.0,5.0,7.0]
var squares: [Double] = []
for value in values {
squares.append(value*value)
}
This works but the boilerplate code to declare the type of the squares
array and then loop over it is a little verbose. We also need to make the squares
array a var as we are changing it in the loop. Now compare to when we use map
:
let values = [2.0,4.0,5.0,7.0]
let squares = values.map {$0 * $0}
// [4.0, 16.0, 25.0, 49.0]
This is a big improvement. We don’t need the for loop as map
takes care of that for us. Also the squares
result is now a let or non-mutating value and we did not even need to declare its type as Swift can infer it.
The shorthand closure syntax can make this hard to follow at first. The map
function has a single argument which is a closure (a function) that it calls as it loops over the collection. This closure takes the element from the collection as an argument and returns a result. The map function returns these results in an array.
Writing the mapping function in long form can make it easier to see what is happening:
let values = [2.0,4.0,5.0,7.0]
let squares2 = values.map({
(value: Double) -> Double in
return value * value
})
The closure has a single argument: (value: Double)
and returns a Double
but Swift can infer this. Also since map
has a single argument which is a closure we do not need the (
and )
and with a single line closure we can even omit the return
:
let squares2 = values.map {value in value * value}
The in
keyword separates the argument from the body of the closure. If you prefer you can go one step further and use the numbered arguments shorthand:
let squares = values.map { $0 * $0 }
The type of the results is not limited to the type of the elements in the original array. Here is an example of mapping an array of integers to strings:
let scores = [0,28,124]
let words = scores.map { NSNumberFormatter.localizedStringFromNumber($0,
numberStyle: .SpellOutStyle) }
// ["zero", "twenty-eight", "one hundred twenty-four"]
The map operation is not limited to Arrays you can use it anywhere you have a collection type. For example, use it with a Dictionary
or a Set
, the result will always be an Array
. Here is an example with a Dictionary:
let milesToPoint = ["point1":120.0,"point2":50.0,"point3":70.0]
let kmToPoint = milesToPoint.map { name,miles in miles * 1.6093 }
Quick tip: If you have trouble understanding the argument types of the closure Xcode code completion will help you:
In this case we are mapping a Dictionary
so as we iterate over the collection our closure has arguments that are a String
and a Double
from the types of the key and value that make up each element of the dictionary.
A final example with a Set:
let lengthInMeters: Set = [4.0,6.2,8.9]
let lengthInFeet = lengthInMeters.map {meters in meters * 3.2808}
In this case we have a set containing elements of type Double
so our closure also expects a Double
.
Filter
Use filter
to loop over a collection and return an Array
containing only those elements that match an include condition.
The filter
method has a single argument that specifies the include condition. This is a closure that takes as an argument the element from the collection and must return a Bool
indicating if the item should be included in the result.
An example that filters as array of integers returning only the even values:
let digits = [1,4,10,15]
let even = digits.filter { $0 % 2 == 0 }
// [4, 10]
Reduce
Use reduce
to combine all items in a collection to create a single new value.
The reduce
method takes two values, an initial value and a combine closure. For example, to add the values of an array to an initial value of 10.0:
let items = [2.0,4.0,5.0,7.0]
let total = items.reduce(10.0,combine: +)
// 28.0
This will also work with strings using the +
operator to concatenate:
let codes = ["abc","def","ghi"]
let text = codes.reduce("", combine: +)
// "abcdefghi"
The combine argument is a closure so you can also write reduce using the trailing closure syntax:
let names = ["alan","brian","charlie"]
let csv = names.reduce("===") {text, name in "\(text),\(name)"}
// "===,alan,brian,charlie"
FlatMap
The simplest use is as the name suggests to flatten a collection of collections.
let collections = [[5,2,7],[4,8],[9,1,3]]
let flat = collections.flatMap { $0 }
// [5, 2, 7, 4, 8, 9, 1, 3]
Even more usefully it knows about optionals and will remove them from a collection.
let people: [String?] = ["Tom",nil,"Peter",nil,"Harry"]
let valid = people.flatMap {$0}
// ["Tom", "Peter", "Harry"]
The real power of flatMap
comes when you use it to produce an Array
which is the flattened concatenation of transforming each of the subarrays.
For example to return an array of even integers contained in a collection of integer arrays by applying a filter to each item in the subarrays:
let collections = [[5,2,7],[4,8],[9,1,3]]
let onlyEven = collections.flatMap {
intArray in intArray.filter { $0 % 2 == 0 }
}
// [2, 4, 8]
Note that flatMap is iterating over the subarrays of integers so its argument is a closure whose argument intArray
is of type [Int]
. This is also a situation where I find the shorthand closure syntax hard to read but you could write this:
let onlyEven = collections.flatMap { $0.filter { $0 % 2 == 0 } }
Another example to produce a flat Array
that contains the squares of each Int
by applying a map
to each subarray and then concatenating the result:
let allSquared = collections.flatMap { $0.map { $0 * $0 } }
or in longer form:
let allSquared = collections.flatMap {
intArray in intArray.map { $0 * $0 }
}
// [25, 4, 49, 16, 64, 81, 1, 9]
A final example that returns the individual sums of each of the arrays of integers by applying reduce
to each of the subarrays:
let sums = collections.flatMap { $0.reduce(0, combine: +) }
Note though as someone helpfully pointed out to me this last example can be achieved with a plain map as reduce is returning an integer not an array:
let sums = collections.map { $0.reduce(0, combine: +) }
Chaining
You can chain methods. For example to sum only those numbers greater than or equal to seven we can first filter and then reduce:
let marks = [4,5,8,2,9,7]
let totalPass = marks.filter{$0 >= 7}.reduce(0,combine: +)
// 24
Another example that returns only the even squares by first mapping and then filtering:
let numbers = [20,17,35,4,12]
let evenSquares = numbers.map{$0 * $0}.filter{$0 % 2 == 0}
// [400, 16, 144]
Quick Summary
Next time you find yourself looping over a collection check if you could use map, filter or reduce:
map
returns anArray
containing results of applying a transform to each item.filter
returns anArray
containing only those items that match an include condition.reduce
returns a single value calculated by calling a combine closure for each item with an initial value.
Swift map filter reduce 使用指南的更多相关文章
- python 内置函数 map filter reduce lambda
map(函数名,可遍历迭代的对象) # 列组元素全加 10 # map(需要做什么的函数,遍历迭代对象)函数 map()遍历序列得到一个列表,列表的序号和个数和原来一样 l = [2,3,4,5,6, ...
- 如何在python3.3用 map filter reduce
在3.3里,如果直接使用map(), filter(), reduce(), 会出现 >>> def f(x): return x % 2 != 0 and x % 3 != 0 ...
- python常用函数进阶(2)之map,filter,reduce,zip
Basic Python : Map, Filter, Reduce, Zip 1-Map() 1.1 Syntax # fun : a function applying to the iterab ...
- 数组的高阶方法map filter reduce的使用
数组中常用的高阶方法: foreach map filter reduce some every 在这些方法中都是对数组中每一个元素进行遍历操作,只有foreach是没有 ...
- lambda,map,filter,reduce
lambda 编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数.返回一个函数对象. func = lambda x,y:x+y fu ...
- Python map filter reduce enumerate zip 的用法
map map(func, list) 把list中的数字,一个一个运用到func中,常和lambda一起用. nums = [1, 2, 3, 4, 5] [*map(lambda x: x**2, ...
- Python中map,filter,reduce,zip的应用
事例1: l=[('main', 'router_115.236.xx.xx', [{'abc': 1}, {'dfg': 1}]), ('main', 'router_183.61.xx.xx', ...
- python几个特别函数map filter reduce lambda
lambda函数也叫匿名函数,即,函数没有具体的名称.先来看一个最简单例子: def f(x): return x**2 print f(4) Python中使用lambda的话,写成这样 g = l ...
- javascript数组详解(js数组深度解析)【forEach(),every(),map(),filter(),reduce()】
Array 对象是一个复合类型,用于在单个的变量中存储多个值,每个值类型可以不同. 创建数组对象的方法: new Array(); new Array(size); new Array(element ...
随机推荐
- linux系统下开机启动流程
在了解开机启动流程之前,还是得先了解一些磁盘的基本知识.磁盘主要由盘片,机械手臂,磁头,主轴马达构成.盘片就是存储数据的物理单位了.然后盘片上我们可以分成扇区(sector)和柱面(cylinder) ...
- ElasticStack系列之十七 & 大文本搜索性能提升方案
1. 什么是大文本?具体是什么? 首先需要理解,ElasticSearch 建立索引完成全文检索的前提是将待检索的信息导入到 ElasticSearch 中.而有的信息对应的正文内容会非常的打,可能达 ...
- 【转载】SQL注入原理讲解
这几篇文章讲的都很不错,我看了大概清除了sql注入是怎么一回事,打算细细研究一下这个知识,另写一篇博客: 原文地址:http://www.cnblogs.com/rush/archive/2011/1 ...
- FFmpeg编码扩展之————编码库的扩展(libfdk-aac)
ffmpeg windows版没有libfdk-acc 请求该地址下载:http://tmod.nmm-hd.org/FFmpeg/
- [转载]详解主流浏览器多进程架构:Chrome、IE
http://www.cnbeta.com/articles/109595.htm 随着Web浏览器重要性的日益突出,恶意软件.木马.间谍软件等网络攻击也呈现逐渐的上升.而面对 如此众多的潜在威胁,为 ...
- <dl>
定义列表 自定义列表不仅仅是一列项目,而是项目及其注释的组合. 自定义列表以 <dl> 标签开始.每个自定义列表项以 <dt> 开始.每个自定义列表项的定义以 <dd&g ...
- 关于mysql-connector-java(JDBC驱动)的一些坑
最近在写一个项目的时候,用了maven仓库里面较新的mysql的JDBC驱动,版本是6.0.6,Mybatis的全局配置是这么写的: <?xml version='1.0' encoding=' ...
- Linux awk工具简单学习记录
awk是一个文本分析工具,它把文件逐行读入,以特定符号将每行切分(默认空格为分隔符),切开的部分再进行各种分析处理. awk其名称得自于它的创始人Alfred Aho .Peter Weinberge ...
- 如何使用optipng压缩png图片
OptiPNG – Google推荐的png图片无损压缩工具下载及使用教程 2014年08月24日 实用软件 暂无评论 optipng png图片无损压缩工具介绍: optipng png图片无损压缩 ...
- CodeForces Contest #1110: Global Round 1
比赛传送门:CF #1110. 比赛记录:点我. 涨了挺多分,希望下次还能涨. [A]Parity 题意简述: 问 \(k\) 位 \(b\) 进制数 \(\overline{a_1a_2\cdots ...