Scala集合的真正强大之处在于带来了其高阶方法。一个高阶方法使用一个函数作为其输入参数。需要特别注意的是,一个高阶方法并不改变集合。下面是Scala集合的一些最主要的高阶方法。
1、map
Scala 集合的map 方法将其输入函数应用到集合中所有元素上,并返回另一个集合。返回的集合具有与调用map 方法的那个集合相同数量的元素。不过,在返回的集合中的元素并不是原始集合中相同的类型。示例如下:
val xs = List(1,2,3,4);
val ys = xs.map((x:Int) => x*10.0);
在上面的代码中,xs 的类型是List[Int],而ys 的类型是List[Double]。
如果一个函数只有一个参数,那么圆括号可以被花括号替换。下面的两个语句等价:
val ys = xs.map((x:Int) => x*10.0);
val ys = xs.map{(x:Int) => x*10.0};
正如前面讲过的,Scala 允许使用运算符标记调用任何方法。要进一步提高可读性,前面的代码也可以写成下面这样:
val ys = xs map {(x:Int) => x*10.0};
Scala 可以从集合的类型推断出传入的参数类型,因此可以忽略掉参数类型。下面两个语句是等价的:
val ys = xs map {(x:Int) => x*10.0};
val ys = xs map {x => x*10.0};
如果一个函数字面量的输入参数只在函数体中使用一次,那么右箭头和该箭头的左侧可以从函数字面量中被删除。我们可以只编写函数字面量的函数体。下面的两个语句是等价的:
val ys = xs map {x => x*10.0};
val ys = xs map {_ * 10.0};
上面代码中,下划线(_)字符代表函数字面量的输入传给map 方法。上面的代码可以被理解为集合xs 中的每个元素乘以10。 总结来说,下面的代码分别代表了相同语句的冗长的版本和简洁的版本:
val ys = xs.map((x:Int) => x*10.0);
val ys = xs map {_ * 10.0};
下面是使用map方法的另一个示例:
// 快速产生0.1, 0.2, 0.3等方式的数字
(1 to 9).map(0.1 * _).foreach(println(_))
// 打印三角形
(1 to 9).map("*" * _).foreach(println(_))
2、flatMap
Scala 集合的flatMap将集合中的所有集合元素展开,并形成单个集合。flatMap 方法类似于map。它接收一个函数作为输入,并将该输入函数应用到集合中的每个元素,并返回另一个集合作为结果。不过,传递给flatMap 的函数为原始集合中的每个元素都生成一个集合。因此,应用该输入函数的结果是一个集合的集合。如果相同的输入函数被传递给map 方法,它将返回一个集合的集合。而flatMap 方法则返回一个flattened集合。
下面的例子描述了flatMap 的使用:
val numbersList = List(List(1,2,3), List(4,5,6), List(7,8,9))
numbersList.flatMap(list => list)
输出结果如下:
res1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
请看下面的代码:
val line = "Scala is fun";
val SingleSpace = " ";
val words = line.split(SingleSpace);
val arrayOfChars = words flatMap {_.toList};
输出结果如下:
arrayOfChars: Array[Char] = Array(S, c, a, l, a, i, s, f, u, n)
集合的toList 方法创建集合中所有元素的一个列表。对于将一个字符串、数组、set、或任何其它集合类型转换为一个list,该方法很有用。
3、filter
方法filter 应用一个断言到集合中的每个元素,并返回另一个集合(由断言返回true 的元素组成)。一个断言是返回一个Boolean 值的函数。它返回true 或false。
val xs = (1 to 100).toList;
val even = xs filter {_%2 == 0};
使用filter方法,按照过滤条件,将原集合中不符合条件的数据过滤掉,输出所有匹配某个特定条件的元素,得到一个序列中的所有偶数:
(1 to 9).filter(line => line % 2 == 0).foreach(println(_))
(1 to 9).filter(_ % 2 ==0).foreach(println) // 与上一句等价
4、foreach
Scala 集合的foreach 方法在集合的每个元素上调用其输入函数,但并不返回任何东西。这类似于map方法。这两个方法间的唯一区别在于map 返回一个集合,而foreach 并不返回任何东西。由于它的副作用,这是一个很少使用的方法。
val words = "Scala is fun".split(" ");
words.foreach(println);
5、reduce
方法reduce 返回单个值。正如其名所暗示的,它将一个集合归约为一个单个的值。方法reduce 的输入函数同时接收两个输入并返回一个值。本质上来说,输入函数是一个可组合和可交换的二元运算符。
请看下面的示例:
val xs = List(2,4,6,8,10);
val sum = xs reduce {(x,y) => x+y};
val product = xs reduce {(x,y) => x*y};
val max = xs reduce {(x,y) => if(x > y) x else y};
val min = xs reduce {(x,y) => if(x < y) x else y};
下面这个示例找出一个语句中最长的单词:
val words = "Scala is fun".split(" ");
val longestWord = words reduce {(w1,w2) => if(w1.length > w2.length) w1 else w2};
reduce和reduceLeft都是从左边的操作数开始,而reduceRight是从右边的操作数开始:
(1 to 9).reduce((v1:Int, v2:Int) => v1 + v2)
(1 to 9).reduce(_ + _)
(1 to 9).reduceLeft(_ + _)
(1 to 9).reduceRight(_ + _)
6、sortWith
使用sortWith函数对集合进行排序:
(1 to 9).sortWith((v1:Int, v2:Int) => v1 > v2).foreach(println(_))
println("=======")
(1 to 9).sortWith(_ > _).foreach(println)
【示例】单词计数程序。
下面是一个Scala版本的单词计数程序,其中演示了集合类上的高阶函数用法。
import scala.io.Source
object WordCount {
def main(args: Array[String]): Unit = {
// 方式1
// val text = List("good good study","day day up")
// val words = text.flatMap(_.split(" "))
// val tuples = words.map((_,1))
// val grouped = tuples.groupBy(_._1)
// val sumed = grouped.mapValues(_.size)
// val sorted = sumed.toList.sortBy(_._2)
// val result = sorted.reverse
// result.foreach(println)
// 方式2
// val text = List("good good study","day day up")
// text.flatMap(_.split(" "))
// .map((_,1))
// .groupBy(_._1)
// .mapValues(_.size)
//// .toList.sortBy(_._2)
// .toList.sortWith(_._2 < _._2)
//// .reverse
// .foreach(println)
// 方式3:简洁写法
val text = Source.fromFile("""word.txt""").getLines().toList
text.flatMap(_.split(" "))
.map((_,1))
.groupBy(_._1)
.mapValues(_.size)
.toList.sortWith(_._2 < _._2)
.foreach(println)
}
}
1 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
2 本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
3 本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
暂无评论内容