地图是什么意思(地图,到处都是flatMap,什么意思?)

/ 0评 / 0

最近加入了一个有趣的年轻同事,提交了很多代码。查看git记录,原来Baxter使用了java8的大量语法特性来重构代码。最常用的是地图,平面地图等等。

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

就像:脱裤子放屁,做的不止一件事。

按照级别,这些职能的范围可以分为三类。几乎无处不在。

不要过度使用

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

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

但是,语言要融合,因为这是趋势。我们不看他们背后的设计,只看他们从api的语义表示水平表达了什么。

我们先来看看它们之间的共性(注意:逻辑完全是netlike,并不适合所有场景),然后拿一些典型的实现来看看这个星球上程序员的表现。

这些抽象的概念

这些函数的对象被称为流。小溪是什么样的东西?请原谅我用了一些不专业的词语来解释。

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

我们简单地分为两类。

语言层面的:比如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)
...

编程模式完全变了,功能有了语义。

顺序和。平行的

如果我们的数组流太大,对于一台计算机来说,有两种方法:顺序处理和并行处理。

一般可以通过并行功能进入并行处理模式。对于大多数本(原创版权www.isoyu.com)地操作,并行化不一定很快。

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

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

功能类型

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

转换。Transformation
动作。Action

转型,典型特征就是懒。

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

行动。当代码真正被触发运行时,上面的一系列转换也会像闸门一样泛滥。典型的如减函数,就是这样。

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

地图和地图。减少

说到map和reduce,每个人都会想到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
&n百思特网bsp;.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开发中经常用到(越来越多的用在服务器端)。

RxJava在语言层面做了一些创新,也有一些忠实的信徒。

语言层面的Lambda

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

它们统称为λ。

计算机编程语言

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

Java Script语言

不能删除Js,比如Array.prototype.*()。它拥有它应该拥有的一切。

目标

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