【Scala】通过【foldLeft】来判断一个List是否是另一个List的子集
2017-09-01 11:17
288 查看
【Scala】通过【foldLeft】来判断一个List是否是另一个List的子集:
我的理解:
(x ,y)中的
y是对lst1的遍历,相当于lst1.foreach(y => ...)
x是表达式(initialBoolean /: lst1) {(x, y) => x && lst2.contains(y)}的返回值,其初始值为initialBoolean = true,initialBoolean是val不可变,但循环迭代的过程是在反复生成新的x
或者也可以采用这种方法:
补充一部分《快学Scala》中关于foldLeft、foldRight的知识
以不同于集合首元素的初始元素开始计算通常也很有用。对于coll.foldLeft(init)(op)的调用将会计算
例如:
将得到
0 - 1 - 7 - 2 - 9 = -19
说明:初始值和操作符的两个分开定义的“柯里化”参数,这样Scala就能用初始值的类型来判断出操作符的类型定义。举例来说,在 List(1, 7, 2, 9).foldLeft(" ")(_ + _)中,初始值是一个字符串,因此操作符必定是一个类型定义为(String, Int) => String的函数。
你也可以用/:操作符来写foldLeft操作,就像这样:
/: 操作符的本意是想让你联想到一棵树的样子。
说明:对/:操作符而言,初始值是第一个操作元。注意,由于操作符以冒号结尾,它是第二个操作元的方法。
Scala同样也提供了foldRight或:\的变体,计算
这些示例看上去并不是很有用。coll.reduceLeft(_ + _)或者coll.foldLeft(0)(_ + _)当然会计算出集合中所有元素之和,但你也可以通过调用coll.sum直接得到这个结果。
折叠有时候可以作为循环的替代,这也是它吸引人的地方。假定我们想要计算某个字符串中字母出现的频率。方式之一是访问每个字母,然后更新一个可变映射。
以下是另一种思考方式。在每一步,将频率映射和新遇到的字母结合在一起,产出一个新的频率映射。这就是折叠:
op是什么呢?左操作元是一个部分填充的映射,右操作元是新字母,结果是扩编后的映射。该映射又被作为下一个op调用的输入,最后的结果是包含所有计数的映射。代码是:
注意这是一个不可变映射,我们在每一步都计算出一个新的映射。
说明:任何while循环都可以用折叠来替代。构建一个把循环中被更新的所有变量结合在一起的数据结构,然后定义一个操作,实现循环中的一步。我并不是说这样做总是好的,但你可能会觉得循环和改值可以像这样被消除是很有趣的一件事。
val list1 = "电影 刘德华".split(" ", -1).toList val list2 = "醉拳 喜剧 刘德华 刘家良 电影 中国香港".split(" ", -1).toList /** * 判断list1是否是list2的子集 * @param lst1 * @param lst2 * @return */ def list2containslist1(lst1:Seq[String],lst2:Seq[String]):Boolean = { val initialBoolean = true (initialBoolean /: lst1) {(x, y) => x && lst2.contains(y)} } println(list2containslist1(list1, list2))
我的理解:
(x ,y)中的
y是对lst1的遍历,相当于lst1.foreach(y => ...)
x是表达式(initialBoolean /: lst1) {(x, y) => x && lst2.contains(y)}的返回值,其初始值为initialBoolean = true,initialBoolean是val不可变,但循环迭代的过程是在反复生成新的x
或者也可以采用这种方法:
补充一部分《快学Scala》中关于foldLeft、foldRight的知识
val coll = ... // 某种 Iterable: Seq、List、Set、Map
以不同于集合首元素的初始元素开始计算通常也很有用。对于coll.foldLeft(init)(op)的调用将会计算
例如:
List(1, 7, 2, 9).foldLeft(0)(_ - _)
将得到
0 - 1 - 7 - 2 - 9 = -19
说明:初始值和操作符的两个分开定义的“柯里化”参数,这样Scala就能用初始值的类型来判断出操作符的类型定义。举例来说,在 List(1, 7, 2, 9).foldLeft(" ")(_ + _)中,初始值是一个字符串,因此操作符必定是一个类型定义为(String, Int) => String的函数。
你也可以用/:操作符来写foldLeft操作,就像这样:
(0 /: List(1, 7, 2, 9))(_ - _)
/: 操作符的本意是想让你联想到一棵树的样子。
说明:对/:操作符而言,初始值是第一个操作元。注意,由于操作符以冒号结尾,它是第二个操作元的方法。
Scala同样也提供了foldRight或:\的变体,计算
这些示例看上去并不是很有用。coll.reduceLeft(_ + _)或者coll.foldLeft(0)(_ + _)当然会计算出集合中所有元素之和,但你也可以通过调用coll.sum直接得到这个结果。
折叠有时候可以作为循环的替代,这也是它吸引人的地方。假定我们想要计算某个字符串中字母出现的频率。方式之一是访问每个字母,然后更新一个可变映射。
val freq = scala.collection.mutable.Map[Char, Int]() for (c <- "Mississippi") freq(c) = freq.getOrElse(c, 0) + 1 //现在freq是Map('i' -> 4, 'M' -> 1, 's' -> 4, 'p' -> 2)
以下是另一种思考方式。在每一步,将频率映射和新遇到的字母结合在一起,产出一个新的频率映射。这就是折叠:
op是什么呢?左操作元是一个部分填充的映射,右操作元是新字母,结果是扩编后的映射。该映射又被作为下一个op调用的输入,最后的结果是包含所有计数的映射。代码是:
(Map[Char, Int]() /: "Mississippi") { (m, c) => m + (c -> (m.getOrElse(c, 0) + 1)) }
注意这是一个不可变映射,我们在每一步都计算出一个新的映射。
说明:任何while循环都可以用折叠来替代。构建一个把循环中被更新的所有变量结合在一起的数据结构,然后定义一个操作,实现循环中的一步。我并不是说这样做总是好的,但你可能会觉得循环和改值可以像这样被消除是很有趣的一件事。
相关文章推荐
- 判断一个List是否是另一个List的子集
- 杭电5505GT and numbers(判断一个数通过累乘他的因子是否可以得到另一个数)
- php判断一个数组是否为另一个数组子集的方法
- 判断一个给定的字符串通过循环移位是否可以包含另一个字符串
- python判断一个集合是否为另一个集合的子集
- 哈希(3) - 判断一个数组是否为另一个数组的子集
- 判断一个给定的字符串通过循环移位是否可以包含另一个字符串
- C#中判断一个集合是否是另一个集合的子集的简单方法
- poj 3630 Phone List 【字典树】【判断一个字符串集里面 是否存在一个字符串是另一个字符串前缀】
- HDOJ-1671 Phone List 字典树的应用----判断一组字符串中是否有一个字符串是另一个字符串的前缀(字典树第二类应用)。
- [C++学习笔记] 链表应用1判断一个集和是否为另一个集合的子集
- python判断一个集合是否为另一个集合的子集方法
- 判断一个字符串是否是另一个字符串的子集
- 判断一个数组是否是另一个数组的子集
- sqlite 一条记录判断一个字段是否like另一个字段
- php判断一个字符串是否被包含在另一个字符串中
- [LeetCode] Is Subsequence 判断一个字符串是否为另一个的子序列
- 如何快速判断一个整数是否可以整除另一个整数的理论分析
- JavaScript 判断一个字符串是否在另一个字符串中
- CCI 1.8 判断一个字符串是否为另一个字符转旋转而得