博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript实现惰性序列之思路和完整代码
阅读量:5746 次
发布时间:2019-06-18

本文共 3897 字,大约阅读时间需要 12 分钟。

  hot3.png

javascript实现惰性序列之思路

惰性序列在后文简称lazy-seq

什么是lazy-seq?

lazy-seq是一个序列(你可以把它想象成一个数组或者链表) 只有在你使用时才会去计算出使用的值并且会把值缓存起来下次再次使用时直接取 缓存中的值

lazy-seq有什么用?

优化函数性能

如果你的函数返回的数据是lazy-seq而不是处理好的数据 处理数据的过程只会在你使用它的时候进行而且精确到某个数据 而你的函数不需要做出什么大的改变

无穷序列(可以想象成无穷大的数组)

拿典型斐波那契数列举例

function fibfn(n){    if(n==0)return 0;    if(n==1)return 1;    return fibfn(n-2)+fibfn(n-1);}

这个能达取斐波那契数列的功能但是换个角度思考下为什么fibfn不能是一个"数组"呢 fibfn是一个无穷大的数组 里面是[0,1,1,2,3,5....]这样更直接更直观

实现思路

简单的序列实现

万事开头难,无头绪。参考链表的数据结构首先先要有能存两个元素的东西有了能存俩的我们就能延伸出无数个了 然后再有能取出这两个元素的东西,开始敲代码

function cons(a,b){    return function(flg){        return {head:a,tail:b}[flg];    }}function head(seq){    return seq('head');}function tail(seq){    return seq('tail');}var b=cons(1,2);head(b)// ->1tail(b) //->2var c=cons(1,cons(2,cons(3,null)));head(c) //->1head(tail(c)) //->2head(tail(tail(c))) //->3

完美 完美 哈哈

lazy-seq实现

我要实现的是lazy-seq是在使用的时候才会求值 而这里的是在cons的时候值就出来了不符合要求 当需要的时候取值初始化的时候第二个参数可以使用函数 当取值的时候调用下而且还要把值给缓存起来

function cons(a,b){		if(typeof b !=="function")throw "arg 2 must is function";		function r(flg){						return {head:a,tail:b}[flg];		}		r.toString=function(){			return "lazy-seq:"+formatCacheValue(r,200);		}		return r;	}	function head(lis){		return lis("head");	}	function tail(lis){		if(lis.cacheValue)return lis.cacheValue;		lis.cacheValue=lis("tail")(lis);		return lis.cacheValue;	}  function isEmptyLs(ls){		return ls===null;	}	function formatCacheValue(ls,deep){		if(isEmptyLs(ls))return "";		if(ls.cacheValue===undefined)return head(ls)+"->wating...";		if(deep==0)return "..."		return head(ls)+"->"+formatCacheValue(ls.cacheValue,deep-1);	}

创建1-10的数列 使用head只能一个一个的取太麻烦了 所以还需要个take函数 取多个数据

take函数实现

function take(n,ls){		if(n<0) throw "arg 1 must >0";		if(n==0)return [];		if(isEmptyLs(ls))return [];		if(n==1)return [head(ls)];		return [head(ls)].concat(take(n-1,tail(ls)));}function create10seq(seq){		if(head(seq)==10)return null;		return cons(head(seq)+1,create10seq);}	//1 2 3 4 5 6 7 8 9 10var l10=cons(1,create10seq);

l10->lazy-seq:1->wating...

head(l10)->1

l10->lazy-seq:1->wating...

take(11,l10)->[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

l10->lazy-seq:1->2->3->4->5->6->7->8->9->10->nil

=完美= =完美=

无穷大lazy-seq,map函数实现

接下来实现一个自然数列 1,2,3,4....无穷大 这个我们需要一些操作lazy-seq的函数 为了简单起见都写成curry的函数

function map(fn){		return function(ls){			return cons(fn(head(ls)),map(fn));		}}function add(a){		return function(b){			return a+b;		}}var l2=cons(1,map(add(1)));

take(10,l2)->[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

take(20,l2)->[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

l2->lazy-seq:1->2->3->4->5->6->7->8->9->10->11->12->13->14->15->16->17->18->19->20->wating...

=完美= =完美=

斐波那契lazy-seq实现

下面实现一个复杂点的数列 斐波那契

function map2(fn){		return function(ls1){			return function(ls2){				return cons(fn(head(ls1))(head(ls2)),map2(fn)(ls2));			}		}}//0,1,1,2,3,5,8.....	var fib=cons(0,function(seq){		return cons(1,map2(add)(seq));	})

take(10,fib)->[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

take(20,fib)->[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]

=一如既往的完美=

filter函数实现

再加个需求 我们取出10个大于100的斐波那契数列

function filter(fn){		return function(ls){			if(isEmptyLs(ls))return null;			var val=head(ls);			if(fn(val))return cons(val,function(){				return filter(fn)(tail(ls));			});			return filter(fn)(tail(ls));		}}

take(10,filter(function(a){return a>100})(fib))->[144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946]

两种实现斐波那契数列性能对比

为了方便我们做一个nth函数

function nth(idx,ls){		if(idx==0)return head(ls);		return nth(idx-1,tail(ls));}  console.time("fibfn");	console.log(fibfn(40));	console.timeEnd("fibfn");	console.time("lazy-seq-fib");	console.log(nth(40,fib));	console.timeEnd("lazy-seq-fib");/*out*>102334155*>fibfn: 1390.397ms*>102334155*>lazy-seq-fib: 0.426ms*/

性能相差好远 =fibfn= 50是它的极限(在我的浏览器中)

看看fib的极限 nth(1471,fib) ->1.1785114478791467e+307

nth(l480,fib) ->Infinity 毫无压力

=完美=

  • 以上代码都在

转载于:https://my.oschina.net/diqye/blog/550116

你可能感兴趣的文章
BZOJ - 3578: GTY的人类基因组计划2
查看>>
【http】post和get请求的区别
查看>>
TFS强制撤销某个工作区的文件签出记录
查看>>
EL表达式无法显示Model中的数据
查看>>
ps6-工具的基础使用
查看>>
linux下使用过的命令总结(未整理完)
查看>>
时间助理 时之助
查看>>
英国征召前黑客组建“网络兵团”
查看>>
PHP 命令行模式实战之cli+mysql 模拟队列批量发送邮件(在Linux环境下PHP 异步执行脚本发送事件通知消息实际案例)...
查看>>
pyjamas build AJAX apps in Python (like Google did for Java)
查看>>
centos5.9使用RPM包搭建lamp平台
查看>>
Javascript String类的属性及方法
查看>>
[LeetCode] Merge Intervals
查看>>
Struts2 学习小结
查看>>
【记录】JS toUpperCase toLowerCase 大写字母/小写字母转换
查看>>
在 Linux 系统中安装Load Generator ,并在windows 调用
查看>>
Visifire charts ToolBar
查看>>
OC中KVC的注意点
查看>>
【洛天依】几首歌的翻唱(无伴奏)
查看>>
ISO8583接口的详细资料
查看>>