erlang 通过尾递归实现双层循环,并抽象出两向量的叉积的一般运算式

当我使用erlang 编程的时候,总是为没有循环而苦恼。连乘法口诀表都很难实现,想想都郁闷。

    然而当你必须要解决循环的时候,你发现了另外一条路。

C语言:

for(int i=1;i<10;i++)

{

for(int j=1;j<10;j++)

{

if(i>=j) printf("%d",i*j);

}

printf("\n");

}

第一层循环和第二层的关系:

i 为第二层的输入,j从  1 迭代到 9

然后 i 和 从1~9 相乘,就是 i 和列表的相乘 ;而元素的收集代码如下:

collect_sequence(Start_V,End_V,Result) -> if

Start_V>End_V ->

Result;

true -> collect_sequence(Start_V,End_V-1,[End_V|Result])

这是一个尾递归调用

将相乘抽象为一个函数MapFun,那么

filter_map(X,Start_V,End_V,MapFun) ->

Lst = collect_sequence(Start_V,End_V,[]),

lists:map(fun(Value) -> MapFun(X,Value) end,Lst).

如下调用

second:filter_map(2,1,9,fun(X,Y)->X*Y end) 就会打印 2和 1~9 相乘的列表

如果在这个上面加一个过滤器的话就类似C语言实现的 if(i>=j)

实现代码如下:

filter_map(X,Start_V,End_V,MapFun,FilterFun) ->

Lst = collect_sequence(Start_V,End_V,[]),

Lst1 = lists:filter(fun(Value) -> FilterFun(X,Value) end,Lst),

lists:map(fun(Value) -> MapFun(X,Value) end,Lst1).

测试用例:

second:filter_map(2,1,9,fun(X,Y)->X*Y end,fun(X,Y)->X>=Y end).

然后我们实现第一层循环

arithmetic(A1_Start,A2_End,B1_Start,B2_Start,MapFun,FilterFun)
->

if

A1_Start>A2_End
->

[];

true ->

io:format("~w~n",[filter_map(A1_Start,B1_Start,B2_Start,MapFun,FilterFun)]),

arithmetic(A1_Start+1,A2_End,B1_Start,B2_Start,MapFun,FilterFun)

end.

测试用例如下:

second:arithmetic(1,9,1,9,fun(X,Y)->
X*Y end,fun(X,Y)-> X>=Y end).

元素从A1_Start 到A2_End终止,区间为[A1_Start,A1_End]

打印为:

[1]

[2,4]

[3,6,9]

[4,8,12,16]

[5,10,15,20,25]

[6,12,18,24,30,36]

[7,14,21,28,35,42,49]

[8,16,24,32,40,48,56,64]

[9,18,27,36,45,54,63,72,81]

[]

最后一个是函数的返回值,其他为九九乘法表输出

我们仅仅是想通过递归实现九九乘法表,最后我们得到了一个通用的函数:

arithmetic(A1_Start,A2_End,B1_Start,B2_Start,MapFun,FilterFun)

这个函数能够处理两组数(两个集合或者说是两个向量)的叉积,得到一个矩阵。而不仅仅是九九乘法表.

arithmetic_list(Lst1,Lst2,MapFun,FilterFun) 是以列表的方式作为输入最后输出一个运算后的矩阵的通用函数

因为没有了循环而被迫使用递归,而正因为实现的艰难发现了更加深刻的外层和内层循环的关系,而得到了一个通用函数。这和列表的通用函数lists:map,lists:filter,lists:reduce 有些类似。上帝关闭了一扇门,会为我们打开一扇窗。

代码如下:

	-module(second).
	-export ([filter_map/5]).
	-export ([collect_sequence/3]).
	-export ([arithmetic/6]).
	-export ([arithmetic_list/4]).

	%% collect_sequence(Start_V,End_V,Result)
	%% 收集 Start_V~End_V 到结果Result中 区间[Start_V,End_V]
	%% Start_V - 左边界
	%% End_V - 右边界
	collect_sequence(Start_V,End_V,Result) -> if
		Start_V>End_V ->
			Result;
		true -> collect_sequence(Start_V,End_V-1,[End_V|Result])
	end.
	% filter_map(X,Start_V,End_V,MapFun,FilterFun)
	filter_map(X,Start_V,End_V,MapFun,FilterFun) ->
		Lst = collect_sequence(Start_V,End_V,[]),
		Lst1 = lists:filter(fun(Value) -> FilterFun(X,Value) end,Lst),
		lists:map(fun(Value)	-> MapFun(X,Value) end,Lst1).
	%arithmetic(A1,A2,B1,B2,MapFun,FilterFun)
	%根据算法F来计算两组数,比如计算[1~9] 和 [1~9] 的乘法口诀表
	%A1_Start 第一组开始值
	%A2_End 第一组终止值
	%B1_Start 第二组开始值
	%B2_Start 第二组终止值
	%F为算法 比如 fun(X,Y) -> X*Y end.
	%% 例子:arithmetic(1,9,1,9,fun(X,Y) -> X*Y end,fun(X,Y) ->X>=Y end).

	arithmetic(A1_Start,A2_End,B1_Start,B2_Start,MapFun,FilterFun) ->
		if
			A1_Start>A2_End ->
				[];
			true ->
				io:format("~w~n",[filter_map(A1_Start,B1_Start,B2_Start,MapFun,FilterFun)]),
				arithmetic(A1_Start+1,A2_End,B1_Start,B2_Start,MapFun,FilterFun)
		end.

	filter_map_list(X,Lst2,MapFun,FilterFun) ->
		TempList = lists:filter(fun(Value) -> FilterFun(X,Value) end,Lst2),
		lists:map(fun(Value) -> MapFun(X,Value) end,TempList).

	%arithmetic_list - 通过 FilterFun,并且通过MapFun来将两个集合(向量)进行运算,
	%得到一个矩阵
	%参数:Lst1 - 第一个集合,Lst2 - 第二个集合,MapFun - 两个集合预算的函数,FilterFun 过滤函数
	%例子:
	%arithmetic_list([1,2,3,4,5,6,7,8,9],[1,2,3,4,5,6,7,8,9],fun(X,Y) ->X*Y end,fun(X,Y)->X>=Y end).

	arithmetic_list([],Lst2,MapFun,FilterFun) -> [];
	arithmetic_list(Lst1,Lst2,MapFun,FilterFun) ->
		[H|T] = Lst1,
		TempLst = filter_map_list(H,Lst2,MapFun,FilterFun),
		io:format("~w~n",[TempLst]),
		arithmetic_list(T,Lst2,MapFun,FilterFun).
时间: 2024-10-10 09:32:39

erlang 通过尾递归实现双层循环,并抽象出两向量的叉积的一般运算式的相关文章

【策略与优化 - 001】- 在特定场景下,如何对双层循环进行降级,加速数据匹配?

一.场景介绍 假设某次搜索结果中有 100_0000 篇文章,而你的个人收藏中有 10000 篇,如何在短时间内快速识别 100_0000 中哪些是 "已收藏", 哪些是 "未收藏" ? 二.正常逻辑(双层for 循环) public class ForEachTest { public static void main(String[] args) { // user book list List<String> ubList = new ArrayL

REQUIRES_NEW 如果不在一个事务那么自己创建一个事务 如果在一个事务中 自己在这个大事务里面在创建一个子事务 相当于嵌套事务 双层循环那种

REQUIRES_NEW   如果不在一个事务那么自己创建一个事务 如果在一个事务中 自己在这个大事务里面在创建一个子事务  相当于嵌套事务 双层循环那种 不管是否存在事务,业务方法总会自己开启一个事务,如果在已有事务的环境中调用,已有事务会被挂起,新的事务会被创建,直到业务方法调用结束,已有事务才被唤醒. 原文地址:https://www.cnblogs.com/classmethond/p/10440510.html

练习:利用循环,遍历出每一个字符

利用循环,遍历出每一个字符 方法一: msg = 'hello egon 666' # print(msg[4]) # 打印字符串msg里索引4位置的字母 # print(len(msg)) count = 0 # 定义初始值 while count < len(msg): # 遍历小于字符串msg的长度 print(msg[count]) # 打印每个字符,此时count是每个字符的索引位置,通过字符串[]的方式取出字符. count += 1 # 自增1 输出结果: h e l l o e

学习笔记-汇编-双层循环

汇编中 循环的语法是 C语言中的循环 mov cs,N   //循环最大次数    <-----> int i=N; blockName: //循环开始 <----->  for(;i>0;i++){ //xxx...   //循环中的语句      <-----> //XXXX loop blockName //循环结束  <-----> } 另附上汇编示例代码 1 assume cs:code 2 code segment 3 start: 4 m

双层循环经典小项目题

# (1) 99 乘法表 方向一 i = 1 while i<=9: # 打印表达式 j = 1 while j <= i: print("%d*%d=%2d " % (i,j,i*j) ,end="") j+=1 # 打印换行 print() i+=1 # 方向二 i = 1 while i<=9: # 打印空格 k = 9 - i while k>0: print(" ",end="") k -=

冒泡排序和双层循环的理解

冒泡排序: Dim liSort() As Short = {5, 3, 1, 7, 6, 11, 234, 23, 1, 543} Dim j As Short = 0 Dim liTemp As Short = 0 第一层循环控制,一共要比较多少轮.总长度 – 1 ,因为最后剩下1位,不需要再进行比较. 第二层循环控制,每一轮要比较多少次.每比较完1轮,就冒泡得到了最大的数字.最大数字不需要再加入比较. For i = 0 To liSort.Length - 2 For j = 0 To

【PHP面向对象(OOP)编程入门教程】4.如何抽象出一个类?

上面已经介绍过了, 面向对象程序的单位就是对象,但对象又是通过类的实例化出来的,所以我们首先要做的就是如何来声明类, 做出来一个类很容易,只要掌握基本的程序语法定义规则就可以做的出来,那么难点在那里呢? 一个项目要用到多少个类,用多少个对象, 在那要定义类,定义一个什么样的类,这个类实例化出多少个对象, 类里面有多少个属性, 有多少个方法等等,这就需要读者通过在实际的开发中就实际问题分析设计和总结了. 类的定义: 1 2 class 类名 { } 使用一个关键字class和后面加上一个你想要的类

Java程序中用for循环语句 写出九九乘法表

今天学习了Java的for循环,用这个写了个九九乘法表,分享给大家.好东东要懂得分享额. 源码如下: for (int i=1;i<=9;i++) {          for (int j=1;j<=i;j++){              System.out.print(i+"*"+j+"="+(i*j)+"\t");          }          System.out.println("");  

php--opp--4.如何抽象出一个类?

上面已经介绍过了, 面向对象程序的单位就是对象,但对象又是通过类的实例化出来的,所以我们首先要做的就是如何来声明类, 做出来一个类很容易,只要掌握基本的程序语法定义规则就可以做的出来,那么难点在那里呢? 一个项目要用到多少个类,用多少个对象, 在那要定义类,定义一个什么样的类,这个类实例化出多少个对象, 类里面有多少个属性, 有多少个方法等等,这就需要读者通过在实际的开发中就实际问题分析设计和总结了. 类的定义: class 类名 { } 使用一个关键字class和后面加上一个你想要的类名以及加