亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

技術專欄 | 集合管道模式(下)

標簽:
Java

译者 | TalkingData 李冰心

原文 |

操作彼此间传递的信息在不同的环境中有着不同的形式:

这种模式也会出现在其它地方。当关系模型首次定义时,其假定所有数据都表示为数学上的关系,就是说n个集合的笛卡儿积的一个子集,数据可以通过关系演算和关系代数的一种方式来操作,你可以将其视作一个集合管道,操作中产生的中间集合被约束为关系。SQL最初作为关系数据库的标准语言而提出,而在实际上总是违背它。所以SQL DBMS实际上不是真正的RDBMS,并且当前ISO SQL标准不提及关系模型或者使用关系术语或概念,SQL使用了一种类似于推导的方式(稍后我会讨论)。

这样一系列转换的概念是软件构建中常见的方法,这也是管道过滤器模式的设计意图。编译器工作原理相似,将源码转换为语法树,途经各种优化,最后输出目标代码。 关于集合管道的区别:各阶段公用的数据结构是集合,最后限定一组特定的公共管道操作。

三、探索更多管道和操作之 map 和 reduce

到目前为止,涉及的是一些常用的管道操作,接下来通过 Ruby 事例代码,让我们来探索更多的操作。诚然使用其它支持该模式的语言,也会构造相同形式的管道。

统计单词总数(map 和 reduce)

Markdown

通过统计所有文章单词总数的例子,让我来介绍下两个最重要的管道操作。

第一个 map:使用给定的 lambda 表达式,作用于输入集合的每个元素,将 lambda 表达式结果以集合的方式返回。

[1, 2, 3].map{|i| i * i} # => [1, 4, 9]

通过使用 map 将文章列表转换为每篇文章单词总数列表。

第二个 reduce:输入集合经过累计运算,最终输出单个结果。具有类似功能的任何函数都可以称作 Reduction,Reduction 在集合管道中总是以终结者的身份最后登场。通常情况下,可以使用两个入参的 lambda 表达式来定义 Ruby 中的 reduce 函数,一个入参是集合元素,一个是累加器。 在 reduce 的过程中,使用 lambda 表达式作用于每个元素,累加器会累计每次 lambda 的返回结果。接下来你可以这样求和:

[1, 2, 3].reduce {|acc, each| acc + each} # => 6

之后使用 map 和 reduce 构造两步操作的管道来统计单词总数。

some_articles
  .map{|a| a.words}
  .reduce {|acc, w| acc + w}

第一步使用 map 将文章列表转换为每篇文章单词数列表,第二步使用 reduce 累计求和。
在这点上,值得一提的是管道上的操作你可以使用不同的方式定义,上面使用的是 lambda,其实仅使用函数名称也是可以的,例如在 Clojure 中:

(->> (articles) 
     (map :words) 
     (reduce +))

该场景中,你只需要关注函数名称,对于 Ruby 也可以使用同样的风格:

some_articles 
    .map(&:words) 
    .reduce(:+)

通常情况下使用函数名称看上去更精炼,但是你会受限于函数的声明和调用方式。lambdas 可以提供更大的灵活性,但是你需要了解更多的语法。关于使用何种语言构造管道,如果 Ruby,我倾向于使用 lambda,如果 Clojure,则是函数名称。具体使用何种方式,你可以自由选择。

四、探索更多管道和操作之 group-by

统计每种类型的文章数(group-by)

Markdown

接下来我们会统计每种类型的文章数,依据统计结果输出的形式,需要使用一个键是类型值是文章数的 hashmap 。
为了解决这个问题,首先我们需要根据类型对所有文章进行分组,这里使用的集合操作就是 group-by,通过使用该操作,会将所有元素射到 hash 中,而索引值依据在此元素上执行给定代码的返回结果。 让我们来看看具体使用的细节:

some_articles
  .group_by {|a| a.type}

然后需要统计每种类型下的文章数。你很可能这样认为,不就是一个简单的 map 操作吗?但实则不然,因为这里需要返回两种维度:分组和数量。这和我们之前介绍 map 的例子有些许联系,但是此时需要使用 group-by 输出 hashmap。
想想开篇中 Unix 的命令行,这个问题在 Unix 中是很常见。集合通常以 list 形式出现,但有时却是 hash,有时候需要在二者之间来回转换。有个取巧的做法是将 hash 视作键值对列表,其中键值对是一种独立结构。关于如何定义 hash 每种语言略有差异,但通常是这样:[key, value]。
Ruby 提供了 to_h 方法可以将数组集合转为 hash:

some_articles
  .group_by {|a| a.type}
  .map {|pair| [pair[0], pair[1].size]}
  .to_h

在管道中 list 和 hash 经常这样互转,但是访问 hash 却需要使用数组下标的方式访问,多少有些怪异,而 Ruby 可以将其解构为两个独立的变量:

some_articles
  .group_by {|a| a.type}
  .map {|key, value| [key, value.size ]}
  .to_h

在函数式编程语言中解构是一种常见的技术,但是传递这些 list-of-hash 数据结构性能上势必会有所损耗。Ruby 的解构语法非常简单,而且足以达到这个简单目的。

同样 Clojure 更是如此:

(->> (articles)
     (group-by :type)
     (map (fn [[k v]] [k (count v)]))
     (into {}))


點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消