知乐空间

到处是map、flatMap,啥意思?(map是什么意思)

最近加入了一个有趣的年轻同事,提交了很多代码。打开git记录,结果发现代码是通过使用java8的大量语法特性重新构建的。最常用的是地图、平面地图等。

但是其他朋友不想。虽然有些人觉得代码变得容易理解,但更多的人觉得代码变得晦涩难懂。

感觉就像:脱裤子放屁,重新发明轮子。

我认为这些功能的范围可以根据级别分为三类。几乎无处不在。

不要过分使用

我不知道这些函数是什么时候流行起来的,但它们与函数编程密切相关。Scala似乎是从2004年开始的。

没什么神奇的。都是语法糖,用来让你的程序更简洁。如果你愿意,你可以用更多的代码来完成。不要故意用它来炫耀你的技能。事情会变得越来越糟。如果用不好,效果会很负面。比如Java不是函数式编程语言,那么lambda只是一个辅助;而如果用java写Lisp代码,只会不伦不类。

但是语言还是需要整合,因为这是趋势。与其看他们背后的设计,不如让我们从api的语义表示来看他们水平表达了什么。

先来看看共性(注意:逻辑共性并不适合所有场景),然后拿几个典型的实现来看看程序员在这个星球上的表现。

这些抽象的概念

这些函数的对象被称为流。具体是什么流程?请原谅我用了一些不专业的词语来解释。

无论是语言层面还是分布式数据结构,其实都是一个简单的数组。有时它确实是一个简单的数组,有时它是一个存在于多台机器中的分布式数组。在下文中,我们将把它统称为数组流。

我们简单地分为两类。

语言层面的:比如Java的Stream分布式层面的:比如Spark的RDD

它们都有以下要点。

函数可以用作参数。

c语言当然没问题。函数可以作为指针传入。但不久前,在java中,这不得不绕过弯道来实现(使用java中的Class概念来模拟函数,你会看到很多奇怪的Java类,比如Func1和Func0)。

函数作为参数是使代码简洁的必要条件。我们通常的编程方法大多是按顺序执行一些操作。

array = new Array()array = func1(array)if(func2(array)){ array = func3(array)array = func4(array)

如果函数可以作为参数,我可以尽可能的平铺操作。最后会翻译成上面的语句执行。

array = new Array()array.stream().map(func1).filter(func2).flatMap(func3).sorted(func4)...

编程模式完全变了,函数有语义。

顺序并行

如果我们的数组流太大,单机有顺序处理和并行处理两种方式。

一般可以通过并行功能进入并行处理模式。对于大多数本地操作,并行启动不一定快。

在java中使用ForkJoin,线程的速度,你知道…

对于分布式数据流,它是并行的,所以这个参数意义不大。

功能类型

通常,作用于数据流的功能可以分为两类。

转换。Transformation动作。Action

转型,典型特征就是懒。

只有当动作被执行时,它才会真正参与操作。因此,您可以认为这些转换操作是一组缓冲操作。地图、平面地图等典型功能。它们像串肉扦一样串在一起,等着被砸碎。

行动。真正的触发代码操作,即上面的一系列转换,也将像闸门打开时的洪水一样。典型的例子是reduce函数,就是这样。

以上描述并不完全正确。例如,python的map可以在执行后输出结果。这让人没面子。

地图缩小

说到映射和缩减,我们都会想到hadoop。然而,这不仅仅是大数据中的一个概念。

对于他们的概念,我们只在下面两行介绍。

地图

将传入函数依次应用于序列的每个元素,并将结果作为新的数组流返回。

减少

Reduce类似于递归概念。最终会降低到一个值。看这个公式:)

reduce([p1,p2,p3,p4],fn) = reduce([fn(p2,p4),fn(p1,p3)])

我们来看看谷歌的经典论文。

《地图缩减:简化数据》

大型集群上的处理”

https://ai.google/research/pubs/pub62

你能来看看吗?:)

地图平面图

这两个函数经常被使用。它们有以下区别:

地图

使用提供的函数对数组流中的每个值执行一次,并进行一一对应。获取具有相同元素数量的数组流。

平面地图

扁平意味着扁平。它使用提供的函数逐个执行数组流中的每个值。获取具有相同元素的数组流。但是,里面的元素也是一个子数组流。在将这些子阵列合并成一个阵列后,大量元素的概率将不同于原始阵列流的概率。

程序员们的表演

java8中的八种流

Java8从一个新的抽象开始,叫做Stream: stream。有了lambda语法,代码可以变得特别清新干净(一切都将是Scala)。

一个非常好的向导:

https://stackify.com/streams-guide-java-8/

火花的RDD操作

spark的核心数据模型是RDD,它是一个有向无环图。它表示一个不可变的、可分区的集合,其中元素可以并行计算。

它是分布式的,但是我们可以看下一个单词计数的例子。

JavaRDD String  textFile = sc.textFile( hdfs://... JavaPairRDD String, Integer  counts = textFile .flatMap(s -  Arrays.asList(s.split(   )).iterator()) .mapToPair(word -  new Tuple2 (word, 1)) .reduceByKey((a, b) -  a + b);counts.saveAsTextFile( hdfs://...

多么熟悉的Api。你一定在Hadoop中见过。

Flink的DataStream

Flink程序是一个执行分布式集合变换(例如,过滤、映射、更新状态、连接、分组、定义窗口、聚合)的例行程序。Flink中的DataStream程序是在数据流上实现的转换。

让我们也来看看它的一段代码。

DataStream Tuple2 String, Integer  counts =// split up the lines in pairs (2-tuples) containing: (word,1)text.flatMap(new Tokenizer())// group by the tuple field  0  and sum up tuple field  1 .keyBy(0).sum(1);

卡夫卡流的运作

Kafka已经成为一个分布式流计算平台。他抽象出了一个KStream和KTable,它们类似于Spark的RDD,有着相似的操作。

KStream可以看作是KTable的更新日志,数据流中的每一条记录都对应着数据库中的每一次更新。

让我们看看它的一段代码。

KTable String, Long  wordCounts = textLines.flatMapValues(value -  Arrays.asList(value.toLowerCase().split( \\W+ ))).groupBy((key, value) -  value).count();wordCounts.toStream().to( streams-wordcount-output , Produced.with(stringSerde, longSerde));

RxJava

RxJava是基于观察者模式的异步任务框架,在Android开发中经常用到(使用的服务器越来越多)。

RX语言层面有所创新,也有一些忠实的信徒。

语言层面的λ

当然,Haskell这种自然的函数式编程语言也有自己的光环。但是其他语言,包括脚本语言和编译语言,也吸收了这些经验。

它们统称为λ。

计算机编程语言

作为最流行的脚本语言,python也有它的lambda语法。最基本的功能,如地图,减少和过滤也存在。

Java Script语言

Js也拉不下来,比如Array.prototype.*()等等。它拥有它应得的一切。

End

还有很多,我就不一一列举了。换句话说,这些功能可以申请专利吗?我非常喜欢它,尽管我很少使用它。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,请发送邮件至 ZLME@xxxxxxxx@hotmail.com 举报,一经查实,立刻删除。

留言与评论(共有 0 条评论)
验证码: