kotlin函数式编程_我最喜欢的Kotlin函数式编程示例

kotlin函数式编程

by Marcin Moskala

通过Marcin Moskala

One of the great things about Kotlin is that it supports functional programming. Let’s see and discuss some simple but expressive functions written in Kotlin.

Kotlin的一大优点是它支持函数式编程。 让我们看一下并讨论一下用Kotlin编写的一些简单但富有表现力的函数。

收集处理 (Collection processing)

Kotlin has some of the best support for collection processing. It is expressive and supports a lot of functions. To see an example, let’s say that we make a system for a University. We need to find the best students that deserve a scholarship. We have following Student model:

Kotlin为收集处理提供了一些最好的支持。 它具有表现力,并支持许多功能。 来看一个例子,假设我们为大学建立了一个系统。 我们需要找到值得奖学金的最好的学生。 我们有以下Student模型:

class Student(val name: String,val surname: String,val passing: Boolean,val averageGrade: Double
)

Now we can make the following processing to get a list of the best 10 students that match all criteria:

现在,我们可以进行以下处理以获取符合所有条件的10名最佳学生的列表:

students.filter { it.passing && it.averageGrade > 4.0 } // 1.sortedBy { it.averageGrade } // 2.take(10) // 3.sortedWith(compareBy({ it.surname }, { it.name })) // 4
  1. We get only students who are passing and with a grade point average of greater than 4.0.

    我们只会招收及格且平均分数高于4.0的学生。
  2. We sort by the average grade.

    我们按平均成绩排序。
  3. We take first 10 students.

    我们招收了前10名学生。
  4. We sort students alphanumerically. The comparator compares surnames first, and if equal then it compares names.

    我们按字母数字排序学生。 比较器首先比较姓氏,如果相等,则比较名字。

What if, instead of alphanumerical order, we need to keep students in the same order as they were before? What we can do is preserve the order using indexes:

如果我们需要让学生保持以前的顺序,而不是字母数字顺序,该怎么办? 我们可以做的是使用索引保留顺序:

students.filter { it.passing && it.averageGrade > 4.0 }.withIndex() // 1.sortedBy { (i, s) -> s.averageGrade } // 2.take(10).sortedBy { (i, s) -> i } // 3.map { (i, s) -> s } // 4
  1. We add current index to every element.

    我们将当前索引添加到每个元素。
  2. We need to destructure value and index before use.

    我们需要在使用前对值和索引进行解构 。

  3. We sort by index.

    我们按索引排序。
  4. We remove index and keep only students.

    我们删除索引,只保留学生。

This shows how simple and intuitive collection processing in Kotlin is.

这表明Kotlin中的收集过程非常简单直观。

电源组 (Powerset)

If you had algebra at your University, then you might remember what a powerset is. For any set, its powerset is the set of all its subsets including this set and the empty set. For instance, if we have the following set:

如果您在大学学习过代数,那么您可能会记得什么是幂集。 对于任何集合,其幂集是其所有子集的集合,包括该集合和空集合。 例如,如果我们有以下设置:

{1,2,3}

{1,2,3}

Its powerset is the following:

其功率集如下:

{{}, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}

{{}, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}

Such a function is very useful in algebra. How can we implement it?

这样的函数在代数中非常有用。 我们如何实施呢?

If you want to challenge yourself, then stop right now and try to solve it yourself first.

如果您想挑战自己,请立即停止并尝试自己解决问题。

Let’s start our analysis from simple observation. If we take any element of the set (like 1), then the powerset will include an equal number of sets with these elements ({1}, {1,2}, {1,3}, {1,2,3}), and without these ({}, {2}, {3}, {2,3}).

让我们从简单的观察开始分析。 如果我们采用集合的任何元素(如1),则幂集将包含与这些元素相等的集合({1}, {1,2}, {1,3}, {1,2,3}) ,而没有这些({}, {2}, {3}, {2,3})

Note that the second is a powerset({2,3}), and the first is a powerset({2,3}) with 1 added to every set. So we can calculate the powerset by taking the first element, calculating the powerset for all others, and returning the sum of the result and the result with the first element added to every set:

请注意,第二个是powerset({2,3}) ,第一个是powerset({2,3}) ,每个集合中都添加了1。 因此,我们可以通过采用第一个元素,计算所有其他元素的幂集,然后返回结果与将第一个元素添加到每个集合中的结果的和,来计算幂集:

fun <T> powerset(set: Set<T>): Set<Set<T>> {val first = set.first()val powersetOfRest = powerset(set.drop(1))return powersetOfRest.map { it + first } + powersetOfRest
}

The above declaration will not work correctly. The problem is with the empty set: first will throw an error when the set is empty. Here, the definition comes with a solution: powerset({}) = {{}}. When we fix it, we will have our algorithm ready:

上面的声明将无法正常工作。 问题出在空集合上:当​​集合为空时, first将引发错误。 在这里,定义附带一个解决方案:powerset({})= {{}}。 修复后,我们将准备好算法:

fun <T> powerset(set: Set<T>): Set<Set<T>> =if (set.isEmpty()) setOf(emptySet())else {val powersetOfRest = powerset(set.drop(1))powersetOfRest + powersetOfRest.map { it + set.first() }}

Let’s see how it works. Let’s say we need to calculate the powerset({1,2,3}). The algorithm will count it this way:

让我们看看它是如何工作的。 假设我们需要计算powerset({1,2,3}) 。 该算法将以这种方式对其进行计数:

powerset({1,2,3}) = powerset({2,3}) + powerset({2,3}).map { it + 1 }

powerset({1,2,3}) = powerset({2,3}) + powerset({2,3}).map { it + 1 }

powerset({2,3}) = powerset({3}) + powerset({3}).map { it + 2}

powerset({2,3}) = powerset({3}) + powerset({3}).map { it + 2}

powerset({3}) = powerset({}) + powerset({}).map { it + 3}

powerset({3}) = powerset({}) + powerset({}).map { it + 3}

powerset({}) = {{}}

powerset({}) = {{}}

powerset({3}) = {{}, {3}}

powerset({3}) = {{}, {3}}

powerset({2,3}) = {{}, {3}} + {{2}, {2, 3}} = {{}, {2}, {3}, {2, 3}}

powerset({2,3}) = {{}, {3}} + {{2}, {2, 3}} = {{}, {2}, {3}, {2, 3}}

powerset({1,2,3}) = {{}, {2}, {3}, {2, 3}} + {{1}, {1, 2}, {1, 3}, {1, 2, 3}} = {{}, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}

powerset({1,2,3}) = {{}, {2}, {3}, {2, 3}} + {{1}, {1, 2}, {1, 3}, {1, 2, 3}} = {{}, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}

The above function can be improved. We can use the let function to make the notation shorter and more compact:

可以改善上述功能。 我们可以使用let函数使符号更短,更紧凑:

fun <T> powerset(set: Set<T>): Set<Set<T>> =if (set.isEmpty()) setOf(emptySet())else powerset(set.drop(1)).let { it+ it.map { it + set.first() }

We can also define this function as an extension function to Collection so we can use this function as if it is the method of Set (setOf(1,2,3).powerset() instead of powerset(setOf(1,2,3))):

我们还可以将此函数定义为Collection的扩展函数,因此可以像使用Set ( setOf(1,2,3).powerset()而不是powerset(setOf(1,2,3)) ):

fun <T> Collection<T>.powerset(): Set<Set<T>> =if (isEmpty()) setOf(emptySet())else drop(1).powerset().let { it+ it.map { it + first() }

One big improvement is to make the powerset tail recursive. In the above implementation, the state of powerset is growing with every iteration (recurrent call), because the state of the previous iteration needs to be kept in the memory.

一项重大改进是使powerset尾递归。 在上面的实现中, powerset的状态随着每次迭代(循环调用)而增长,因为前一个迭代的状态需要保留在内存中。

Instead, we could use an imperative loop or the tailrec modifier. We will use the second option to maintain the readability of the function. The tailrec modifier allows only a single recursive call in the last statement. This is how we can change our function to use it effectively:

相反,我们可以使用命令式循环或tailrec修饰符。 我们将使用第二个选项来保持功能的可读性。 tailrec修饰符仅允许在最后一条语句中进行单个递归调用。 这是我们可以更改功能以有效使用它的方法:

fun <T> Collection<T>.powerset(): Set<Set<T>> = powerset(this, setOf(emptySet()))private tailrec fun <T> powerset(left: Collection<T>, acc: Set<Set<T>>): Set<Set<T>> =if (left.isEmpty()) accelse powerset(left.drop(1), acc + acc.map { it + left.first() })

The above implementation is part of the KotlinDiscreteMathToolkit library, which defines a lot of other functions used in discrete math.

上面的实现是KotlinDiscreteMathToolkit库的一部分,该库定义了离散数学中使用的许多其他函数。

快速排序 (Quicksort)

Time for my favorite example. We’ll see how a difficult problem can be simplified and made highly readable using a functional programming style and tools.

现在是我最喜欢的例子。 我们将看到如何使用功能性编程风格和工具简化难题并使其具有更高的可读性。

We will implement the Quicksort algorithm. The algorithm is simple: we choose some element (pivot) and we distribute all other elements to the list with bigger and smaller elements than the pivot. Then we recursively sort these sub-arrays. Finally, we add the sorted list of smaller elements, the pivot, and the sorted list of bigger elements. For simplification, we will take the first element as a pivot. Here is the full implementation:

我们将实现Quicksort算法。 该算法很简单:我们选择一些元素(数据透视),然后将所有其他元素分布到列表中,其中元素的大小大于数据透视。 然后,我们对这些子数组进行递归排序。 最后,我们添加较小元素的排序列表,数据透视表和较大元素的排序列表。 为了简化,我们将第一个元素作为枢轴。 这是完整的实现:

fun <T : Comparable<T>> List<T>.quickSort(): List<T> = if(size < 2) thiselse {val pivot = first()val (smaller, greater) = drop(1).partition { it <= pivot}smaller.quickSort() + pivot + greater.quickSort()}
// Usage
listOf(2,5,1).quickSort() // [1,2,5]

Looks great, doesn’t it? This is the beauty of functional programming.

看起来不错,不是吗? 这就是函数式编程的美。

The first concern of such a function is its execution time. It is not optimized for performance at all. Instead, it is short and highly readable.

这种功能首先要考虑的是它的执行时间。 根本没有针对性能进行优化。 相反,它很简短并且可读性强。

If you need a highly optimized function, then you can use one from the Java standard library. It is based on different algorithms depending on some conditions, and it has actual implementations written naively. It should be much more efficient. But how much exactly? Let’s compare these two functions. Let’s sort a few different arrays with random elements and compare execution times. Here is the code I’ve used for this purpose:

如果需要高度优化的功能,则可以使用Java标准库中的一种。 它基于某些条件基于不同的算法,并且天真的编写了实际的实现。 它应该更加有效。 但是多少呢? 让我们比较这两个函数。 让我们用随机元素对几个不同的数组进行排序,并比较执行时间。 这是我用于此目的的代码:

val r = Random()
listOf(100_000, 1_000_000, 10_000_000).asSequence().map { (1..it).map { r.nextInt(1000000000) } }.forEach { list: List<Int> ->println("Java stdlib sorting of ${list.size} elements took ${measureTimeMillis { list.sorted() }}")println("quickSort sorting of ${list.size} elements took ${measureTimeMillis { list.quickSort() }}")}

On my machine I got the following result:

在我的机器上,我得到以下结果:

Java stdlib sorting of 100000 elements took 83quickSort sorting of 100000 elements took 163Java stdlib sorting of 1000000 elements took 558quickSort sorting of 1000000 elements took 859Java stdlib sorting of 10000000 elements took 6182quickSort sorting of 10000000 elements took 12133`

Java stdlib排序100000个元素花费83quickSort排序100000个元素花费163Java stdlib排序1000000个元素花费558quickSort排序1000000个元素花费859Java stdlib排序10000000个元素花费6181quickSort排序10000000个元素花费12133`

As we can see, the quickSort function is generally 2 times slower. Even for huge lists. It has the same scalability. In normal cases, the difference will generally be between 0.1ms vs 0.2ms. Note that it is much simpler and more readable. This explains why in some cases we can use a function that’s a bit less optimized, but readable and simple.

如我们所见, quickSort 功能通常要慢2倍。 即使是巨大的清单。 它具有相同的可伸缩性。 在正常情况下,差异通常在0.1ms与0.2ms之间。 请注意,它更加简单易读。 这就解释了为什么在某些情况下我们可以使用优化程度略低但可读性和简单性强的函数。

If you are interested in Kotlin, check out Kotlin Academy. It is great publication and community dedicated for Kotlin.

如果您对Kotlin感兴趣,请访问Kotlin Academy 。 这是Kotlin的重要出版物和社区。

I am also publishing great resources on my Twitter. To mention me there use @marcinmoskala. If you can use my help, remember that I am open for consultations.

我还在Twitter上发布了大量资源。 要在这里提及我,请使用@marcinmoskala 。 如果可以使用我的帮助,请记住我愿意接受咨询 。

翻译自: https://www.freecodecamp.org/news/my-favorite-examples-of-functional-programming-in-kotlin-e69217b39112/

kotlin函数式编程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/394953.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库收缩

1.选中数据库-任务-收缩-数据库 2.全部压缩 3.右键数据库&#xff0c;属性 4.找到自动收缩&#xff0c;设置为true 转载于:https://www.cnblogs.com/RogerLu/p/10469819.html

matlab自带kfcm函数,kfcmFun.m

function [center, U, obj_fcn] kfcmFun(data, cluster_n,maxit, kernel_b,expo)data_n size(data, 1); % 求出data的第一维(rows)数,即样本个数obj_fcn zeros(100, 1);% 初始化输出参数obj_fcnU initkfcm(cluster_n, data_n);% 初始化模糊分配矩阵,使U满足列上相加为1inde…

flink sql udf jar包_Flink 生态:一个案例快速上手 PyFlink

简介&#xff1a; Flink 从 1.9.0 版本开始增加了对 Python 的支持&#xff08;PyFlink&#xff09;&#xff0c;在刚刚发布的 Flink 1.10 中&#xff0c;PyFlink 添加了对 Python UDFs 的支持&#xff0c;现在可以在 Table API/SQL 中注册并使用自定义函数。PyFlink 的架构如何…

赛思互动:为什么越来越多的企业愿意接受SaaS服务?

SaaS是Software-as-a-Service&#xff08;软件即服务&#xff09;的简称&#xff0c;随着互联网技术的发展和应用软件的成熟&#xff0c; 在21世纪开始兴起的一种完全创新的软件应用模式。SaaS 应用软件的价格通常为“全包”费用&#xff0c;囊括了通常的应用软件许可证费、软件…

使用Google Cloud Platform分散您的应用程序

by Simeon Kostadinov通过Simeon Kostadinov 使用Google Cloud Platform分散您的应用程序 (Decentralize your application with Google Cloud Platform) When first starting a new software project, you normally choose a certain programming language, a specific frame…

pta通讯录排序用python实现,python实现将android手机通讯录vcf文件转化为csv

经常会遇到将手机通讯录导出到电脑并转化为在电脑中可编辑的情况&#xff0c;在网上搜索了很久当前不外乎两种处理方式。1.使用电脑的outlook的通讯簿功能&#xff0c;将手机导出的vcf文件导入到outlook的通讯录中&#xff0c;然后再导出为可编辑文件&#xff1b;2.是使用专用软…

从物联网发展历程看区块链挑战

2009年&#xff0c;中本聪发布了第一个比特币节点&#xff0c;五年后区块链俨然成为一个规模巨大的产业。 虽然看起来&#xff0c;基于区块链的新的商业时代距离我们似乎只有一步之遥&#xff0c;但在2016年&#xff0c;我们已经意识到区块链产业不会那么快获得成功。 早期的新…

编程软件python是什么意思_程序员Python编程必备5大工具,你用过几个?

Python是编程入门不错的选择&#xff0c;现在也有不少的程序员业余时间会研究这门编程语言。 学习Python有时候没有第一时间找到好工具&#xff0c;会吃不少的苦头。毕竟好的工具能将工作效率多倍速提升。下面W3Cschool给小伙伴们推荐Python编程必备的5大工具&#xff1a; 0、I…

Linux ReviewBoard安装与配置

目录 0. 引言1. 安装步骤2. 配置站点 2.1 创建数据库2.2 开始安装2.3 修改文件访问权限2.4 Web服务器配置2.5 修改django相关配置正文 回到顶部0. 引言 环境&#xff1a;Ubuntu 14.04 Server&#xff08;虚拟机&#xff09; 这篇文章里说的是review board官方的安装方式&#x…

小程序 graphql_GraphQL应用程序中的五个常见问题(以及如何解决)

小程序 graphqlby Sacha Greif由Sacha Greif GraphQL应用程序中的五个常见问题(以及如何解决) (Five Common Problems in GraphQL Apps (And How to Fix Them)) 了解如何释放GraphQL的强大功能而不会遭受缺点 (Learn to unlock the power of GraphQL without suffering its dr…

又拍云 php5月18号那,又拍云文档中心

移动流量平台概述又拍云手机流量营销平台&#xff0c;整合移动、电信、联通三大运营商流量资源&#xff0c;将强大的流量营销服务&#xff0c;通过接口等形式提供给商家合作伙伴&#xff0c;帮助商家开展品牌宣传、APP/游戏/微信公众号/网站的拉新与促活等多种营销活动。通过接…

SQL SERVER2000将多行查询结果拼接到一行数据及函数的创建

处理前的查询结果如上图&#xff1a; 通过借助SQL变量的定义 DECLARE Scope varchar(1000) DECLARE Num int SET Scope SET Num 1 SELECT ScopeScopeconvert(varchar(8),Num)、DescScope DescOper;, Num Num1 From fuel_contractQualityNew Where ContractID0120090001…

kindeditor简单使用

先引入&#xff1a; <script src"/static/jquery-3.3.1.min.js"></script><script src"/static/kindeditor-4.1.11-zh-CN/kindeditor/kindeditor-all.js"></script> 基本使用参数&#xff1a; $(function () {KindEditor.create(#…

windows nginx c++读取请求数据_轻松应对百万并发的Nginx,搞懂LinuxC/C++这些技术栈升职加薪...

在深入了解 Nginx 各种原理及在极端场景下的一些错误场景处理时&#xff0c;需要首先理解什么是网络事件。Nginx 是一个事件驱动的框架&#xff0c;所谓事件主要指的是网络事件&#xff0c;Nginx 每个网络连接会对应两个网络事件&#xff0c;一个读事件一个写事件。在深入了解 …

github 6月开源项目_我的开源项目如何在短短5天内在GitHub上赢得6,000颗星

github 6月开源项目Last month I launched two open source projects on GitHub. A few days later, my Front-End Checklist was showing more than 6,000 stars (17,000 as of writing). And I got 600 stars for my Resources-Front-End-Beginner project!上个月&#xff0c…

如何成为一位牛逼的高手

郑昀 演讲稿 创建于2016/9/15 最后更新于2016/9/21 很多人都在思考一个问题&#xff1a; 怎样才能想出来一个牛逼的 idea&#xff1f; 有一位喜欢抽烟喝酒烫头的大师 给出了答案&#xff1a; 这事儿吧&#xff0c;简单&#xff0c;一共分两步。 第一步先让自己成为一个牛逼的人…

thinkphp html php文件,ThinkPHP生成静态HTML文件

View.class.php/*** 加载模板和页面输出 可以返回输出内容* access public* param string $templateFile 模板文件名* param string $charset 模板输出字符集* param string $contentType 输出类型* param string $content 模板输出内容* param string $prefix 模板缓存前缀* r…

day01语法python入门_2

十&#xff1a;while循环 1.基本循环 while条件#循环体#如果条件为真&#xff0c;那么循环体则执行#如果条件为假&#xff0c;那么循环体不执行。2.break break 用于退出所有循环 while True:print "123"breakprint "456"3.continue while True:print &quo…

Python dict() 函数

Python dict() 函数 Python 内置函数 描述 dict() 函数用于创建一个字典。 语法 dict 语法&#xff1a; class dict(**kwarg) class dict(mapping, **kwarg) class dict(iterable, **kwarg) 参数说明&#xff1a; **kwargs -- 关键字mapping -- 元素的容器。iterable -- 可迭代…

贝塞尔曲线:原理、自定义贝塞尔曲线View、使用!!!

一、原理 转自&#xff1a;http://www.2cto.com/kf/201401/275838.html Android动画学习Demo(3) 沿着贝塞尔曲线移动的Property Animation Property Animation中最重要&#xff0c;最基础的一个类就是ValueAnimator了。Property Animation利用ValueAnimator来跟踪记录对象属性已…