Prolog 列表练习 2

本文介绍了Prolog中处理列表的几种操作,包括游程编码(encode)、游程编码的衍生版本(encode_modified)、解码(decode)、直接游程编码(encode_direct)、重复元素(dupli)、重复指定次数(dupli)、删除第N个元素(drop)、列表分割(split)、切片操作(slice)、列表循环移位(rotate)、删除指定元素(remove_at)、元素插入(insert_at)、随机选择(rnd_select)、随机数列表(lotto)、随机排列(rnd_permu)、组合生成(combination)和元素分组(group3)。这些操作展示了Prolog在处理列表和序列数据时的灵活性和强大功能。

转载自:https://mp.weixin.qq.com/s/G1rBTwds5bkObtQfHq5YDw

(注意:程序段行首的数字是为了注释单独编制的行号,后面的注释是对应行号写的)

10、列表的游程编码

 encode(L1,L2):-通过游程长度编码从列表L1获得列表L2。

元素的连续重复项被编码为项[N,E],其中N是元素E的重复项数。

 

1  encode(L1,L2) :- 

pack(L1,L), 

transform(L,L2).

4

5  transform([],[]).

6  transform([[X|Xs]|Ys],[[N,X]|Zs]) :- 

7 length([X|Xs],N), 

8 transform(Ys,Zs).

注释行:

1.L1编码后的列表为L2

2. 如果列表L1 是各自打好包的列表的列表L

3. 并且L2是列表L编码后的列表

4.

5. 空列表的编码列表是空列表

6.

7. 算好包中(列表)元素的长度N,和[N,X]合取

8. 继续编码后续包(递归)

 

?- consult('p1_09.pl').

true.

 

?- consult('p1_10.pl').

true.

 

?- encode([a,a,a,a,b,c,c,a,a,d,e,e,e,e],X).

X = [[4, a], [1, b], [2, c], [2, a], [1, d], [4, e]] .

 

 

11、列表的游程编码衍生版本

通过游程(run-length)编码从列表L1获得列表L2。元素的连续重复项被编码为

项[N,E],其中N是元素E的重复项数。

 但是,如果N等于1,则将元素简单地复制到输出列表中。

 

1  encode_modified(L1,L2) :- 

2 encode(L1,L),

3 strip(L,L2). 

4

5  strip([],[]).

6   strip([[1,X]|Ys],[X|Zs]) :-

7 strip(Ys,Zs).

8   strip([[N,X]|Ys],[[N,X]|Zs]) :- 

9 N > 1,  

10 strip(Ys,Zs). 

注释行:

1. L1编码后的列表为L2

2. 如果列表L1 是各编码好包的列表的列表L

3. 并且L2是列表L编码后的列表

4. 

5. 空列表的编码列表是空列表

6. 当N等于1([1,X]|Ys])时直接将元素放入主表内不另列

7. 继续编码后续包(递归)

8. 取[[X|Xs]|Ys]列表中的打好的包

9. 算好包中(列表)元素的长度N,和[N,X]合取

10.继续编码后续包(递归)

 

?- consult('p1_09.pl').

true.

 

?- consult('p1_10.pl').

true.

 

?- consult('p1_11.pl').

true.

 

?- encode_modified([a,a,a,a,b,c,c,a,a,d,e,e,e,e],X).

X = [[4, a], b, [2, c], [2, a], d, [4, e]] .

 

 

12、解码游程压缩列表

 

decode(L1,L2) 将列表L1解码到列表L2

 

1  decode([],[]).

2  decode([X|Ys],[X|Zs]) :- 

3 \+ is_list(X), 

4 decode(Ys,Zs).

5  decode([[1,X]|Ys],[X|Zs]) :- 

decode(Ys,Zs).

7  decode([[N,X]|Ys],[X|Zs]) :- 

8 N > 1, 

9 N1 is N - 1, 

10 decode([[N1,X]|Ys],Zs).

 

注释行:

1. 空列表解码后的列表仍为空列表

2. 列表[X|Ys]解码后的列表为[X|Zs]

3. 如果元素X不是列表,将元素X直接放入[X|Zs]中

4. 继续解码后续包

5. 如果要解码包列表的首元素是1则将元素X直接放入[X|Zs]中

6. 继续解码后续包

7. 列表[[N,X]|Ys]解码后的列表为[X|Zs]

8. 如果N大于1

9. 并且 N减以后赋值给N1,

10.继续递归剩余部分

 

?- consult(p1_12).

true.

 

?- decode([[4, a], [1, b], [2, c], [2, a], [1, d], [4, e]],X),write('X = '),write(X),nl.

X = [a,a,a,a,b,c,c,a,a,d,e,e,e,e]

X = [a, a, a, a, b, c, c, a, a|...] .

 

?- decode([[4, a], b, [2, c], [2, a], d, [4, e]],X),write('X = '),write(X),nl.

X = [a,a,a,a,b,c,c,a,a,d,e,e,e,e]

X = [a, a, a, a, b, c, c, a, a|...] .

 

 

13、列表的游程长度编码(直接解决方案)

encode_direct(L1,L2):- 通过游程长度编码从列表L1获得列表L2。元素的连续重复项被编码为项[N,E],其中N是元素E的重复项数。但是,如果N等于1,则该元素将被简单地复制到输出列表中。

 

1  encode_direct([],[]).

2  encode_direct([X|Xs],[Z|Zs]) :-  

3 count(X,Xs,Ys,1,Z),     

4 encode_direct(Ys,Zs).   

 

注释行:

1. 

2. X是指一组连续相同元素的那个元素

3. 处理X那组元素,Ys是剩余元素组的列表

4. 递归后续元素组

 

count(X,Xs,Ys,K,T)Ys是在删除X的所有前导副本时仍保留在列表Xs中的列表T是项[N,X],其中NK加上可以从Xs中删除的X的数目N=1的情况下,TX而不是项[1,X]。

 

1  count(X,[],[],1,X).

2  count(X,[],[],N,[N,X]) :-

3 N > 1.

4  count(X,[Y|Ys],[Y|Ys],1,X) :- 

5 X \= Y.

6  count(X,[Y|Ys],[Y|Ys],N,[N,X]) :- 

7 N > 1, 

8 X \= Y.

9  count(X,[X|Xs],Ys,K,T) :- 

10 K1 is K + 1,

11 count(X,Xs,Ys,K1,T). 

 

注释行:

1. X是最后一组元素,当X元素个数为1时

2. X是最后一组元素,当X元素个数为1时

3. X也是整个表的最后一个元素

4. 当只有一个元素时,设置值为1

5. 如果当前元素与后一个元素不等则终止条件成立

6. 

7. 如果X这组元数的个数不止一个元素时,

8. 并且此时是最后一个元素时终止条件成立

9. 元素相同时

10. 如果统计数增1

11.然后继续递归遍历下一个相同元素

 

?- consult('p1_13.pl').

true.

 

?- encode_direct([a,a,a,a,b,c,c,a,a,d,e,e,e,e],X).

X = [[4, a], b, [2, c], [2, a], d, [4, e]] .

 

 

14、重复列表中的元素

dupli(L1,L2) :- L1为原列表,L2为是将L1中每个元素重复一次后的表

 

1  dupli([],[]).

2  dupli([X|Xs],[X,X|Ys]) :- 

3 dupli(Xs,Ys).

 

注释行:

1.  空列表重复后的列表任然为空列表

2. 将列表[X|Xs]中的元素X放两个到后面的列表中如[X,X|Ys]

3. 递归后续列表中的元素

 

?- consult('p1_14.pl').

true.

 

?- dupli([a,b,c,c,d],X).

X = [a, a, b, b, c, c, c, c, d|…].

 

?- dupli(X,[a,a,b,b,c,c,c,c,d,d]).

X = [a, b, c, c, d].

 

 

15、重复给定列表元素的次数

dupli(L1,N,L2) :-L2是通过将所有元素复制N次而从L1获得的。

 

1  dupli(L1,N,L2) :-  

2 dupli(L1,N,L2,N).

 

dupli(L1,N,L2,K) :- L2是通过将L1的每个元素复制N倍,K作为递归时的计数。

 

3  dupli([],_,[],_).

4  dupli([_|Xs],N,Ys,0) :- 

5 dupli(Xs,N,Ys,N).

6  dupli([X|Xs],N,[X|Ys],K) :-

7 K > 0,

8 K1 is K - 1,  

9 dupli([X|Xs],N,Ys,K1). 

 

?- consult('p1_15.pl').

true.

 

注释行:

1. 列表L2是列表L1中相应元素的N倍个

2. 如果列表L2是列表L1中相应元素的N倍个,第四个参数N作为过度数

3. 空列表的N倍元素依然是空列表

4. 当某元素增倍计数为0

5. 递归开启下一个元素

6. 倍增首元素

7. 如果K大于0

8. 并且K减小1

9. 接着递归增加元素

 

?- dupli([a,b,c,c,d],4,X),write('X = '),write(X),nl.

X = [a,a,a,a,b,b,b,b,c,c,c,c,c,c,c,c,d,d,d,d]

X = [a, a, a, a, b, b, b, b, c|...] .

 

 

16、从列表中删除第N个元素

drop(L1,N,L2):-删除列表L1中的第N个元素得到的新表是L2。

 

1  drop(L1,N,L2) :- 

2 drop(L1,N,L2,N).

 

drop(L1,N,L2,K):-通过首先复制K-1元素从L1获得L2,然后删除一个元素,此后,删除第N个元素。

 

3  drop([],_,[],_).

4  drop([_|Xs],N,Ys,1) :- 

5 length(Xs, R),

6 drop(Xs,N,Ys,R).

7  drop([X|Xs],N,[X|Ys],K) :- 

8 K > 1,

9 K1 is K - 1, 

10 drop(Xs,N,Ys,K1).

 

注释行:

1. 词谓词成功

2. 如果此谓词成功

3. 空列表不管删除什么目标列表也都是空列表

4. 到达指定位置成立

5. 获取剩余元素个数

6. 忽略指定的元素继续递归调用成功

7. 没到达指定位置将当前元素加入到新表

8. 确定如果没到达指定位置

9. 指定位置标识K减去1后赋值给K1

10.继续递归处理后续的元素

 

?- consult('p1_16.pl').

true.

 

?- drop([1,2,3,4,5,6,7,8,9],3,X).

X = [1, 2, 4, 5, 7, 8] .

 

17、将列表分为两部分

split(L,N,L1,L2) :- 列表L1包含列表L的前N个元素,列表L2包含其余元素。

 

1  split(L,0,[],L).

2  split([X|Xs],N,[X|Ys],Zs) :-

3 N > 0

4 N1 is N - 1,

5 split(Xs,N1,Ys,Zs).

 

注释行:

1. 列表L从位置0开始分则前一列表为空,后一列表也就是它本身

2. 取列表[X|Xs]中的元素X,将X放到列表

3. 确定N大于0

4. 然后 N减掉1 赋值给N1

5. 继续递归处理列表中下一个元素

 

?- consult('p1_17.pl').

true.

 

?- split([a,b,c,d,e,f,g,h,i,j,k],3,L1,L2).

L1 = [a, b, c],

L2 = [d, e, f, g, h, i, j, k] .

 

 

18、从列表中提取一个切片

slice(L1,I,K,L2) :- 给定两个索引I和K,切片是包含原始列表的第I和第K个元素之间的元素的列表(包括两个限制)。从1开始计算元素。

 

1  slice([X|_],1,1,[X]).

2  slice([X|Xs],1,K,[X|Ys]) :-

3 K > 1,

4 K1 is K - 1,

5 slice(Xs,1,K1,Ys).

6  slice([_|Xs],I,K,Ys) :-

7 I > 1,

8 I1 is I - 1, 

9 K1 is K - 1,

10 slice(Xs,I1,K1,Ys).

 

注释行:

1. 将列表[X|_]从1到1切片得到的子列表为[X]

2. 将列表[X|Xs]从1到K切片得到的子列表为[X|Ys](取元素X到新列表)

3. 确保K大于1,

4. K减1 赋值给K1

5. 递归处理余下的元素

6. 将列表[_|Xs]从IK切片得到的子列表为Ys

7. 确保I大于0

8. 然后I减1赋值给I1

9. 同时将K减1的值赋值给K1

10.继续递归处理后续元素(这里调用第二个子句)

 

?- consult('p1_18.pl').

true.

 

?- slice([a,b,c,d,e,f,g,h,i,j,k],4,8,L).

L = [d, e, f, g, h] .

 

 

 

19将列表循环移N个位置当N值为整循环左移,负值时为循环右移

 

 

:- ensure_loaded(p1_17).

 

1  rotate([],_,[]) :- 

2 !.

3  rotate(L1,N,L2) :-

4 length(L1,NL1),

5 N1 is N mod NL1

6 split(L1,N1,S1,S2),

7 append(S2,S1,L2).

 

注释行:

1. 

2. 

3. 列表L1循环移位N后的列表为L2

4. 确定列表L1的长度为NL1

5. 求N与NL1的余数赋值给N1 注意 (-3 mod 5 = 2)

6. 按求得的N1值将列表L1分成两个列表S1和S2

7. 将列表S2后接S1生成表L2

 

?- consult('p1_19.pl').

true.

 

?- rotate([a,b,c,d,e,f,g,h],3,X).

X = [d, e, f, g, h, a, b, c] .

 

?- rotate([a,b,c,d,e,f,g,h],-2,X).

X = [g, h, a, b, c, d, e, f] .

 

 

20、删除列表中指定元素。

当列表[X|Xs]的首元素是指定元素时成功,第4个参数将忽略指定元素X

1  remove_at(X,[X|Xs],1,Xs).

2  remove_at(X,[Y|Xs],K,[Y|Ys]) :- 

3 K > 1,

4 K1 is K - 1,

5 remove_at(X,Xs,K1,Ys).

 

注释行:

1. 

2. 当列表[Y|Xs]的首元素不是指定元素(K不等于1)

3. 确定K是大于1的

4. 将K减1的值赋给K1

5. 继续递归后续元素

 

?- consult('p1_20.pl').

true.

 

?- remove_at(X,[a,b,c,d,e,f,g,h],4,R).

X = d,

R = [a, b, c, e, f, g, h] .

 

 

21、将元素插入到列表的指定位置

:

  • ensure_loaded(p1_20).

 

%将元素X插入到列表L中的第K位,结果列表为R

insert_at(X,L,K,R) :- 

remove_at(X,R,K,L).

 %列表L是删除列表R指定第K位的元素X后的表

 

?- consult('p1_21.pl').

true.

 

?- insert_at(1234,[a,b,c,d],2,L).

L = [a, 1234, b, c, d] .

 

 

22、创建一个给定整数范围的自然数列表

 

1  range(I,I,[I]).

2  range(I,K,[I|L]) :- 

3 I < K

4 I1 is I + 1, 

5 range(I1,K,L).

 

注释行:

1. 从I开始到I结束的列表为[I]

2. 从I开始到K结束的列表为[I|L]

3. 确保 I 小于 K

4. 将I增1后的值赋给I1

5. 递归继续处理后续自然数

 

?- consult('p1_22.pl').

true.

 

?- range(4,9,L).

L = [4, 5, 6, 7, 8, 9] .

 

 

23、取出列表中指定数量的元素,并且这些元素是随机取的

 

:- ensure_loaded(p1_20).

 

1  rnd_select(_,0,[]). 

2  rnd_select(Xs,N,[X|Zs]) :-  

3 N > 0,

4 length(Xs,L),

5 I is random(L) + 1,

6 remove_at(X,Xs,I,Ys),

7 N1 is N - 1, 

8 rnd_select(Ys,N1,Zs). 

 

 

注释行:

1. 取0个元素的列表是空列表

2. 将从列表Xs取出的元素X添加到列表[X|Zs]中

3. 确保N大于0

4. 计算列表Xs的长度为L(元素的个数为0)

5. 插身随机数(+1是避免随机数是0)

6. 移除列表Xs中指定位置为I,的元素X

7. 将N减1的值赋给N1

8. 继续递归取后续元素谓词

 

?- consult('p1_23.pl').

true.

 

?- rnd_select([a,b,c,d,e,f,g,h,1,2,3,4,5],4,L).

L = [h, 4, d, b] .

 

 

24lotto 1..M中抽取N个不同的随机数。

 

1  :- ensure_loaded(p1_22).

2  :- ensure_loaded(p1_23).

3

4  lotto(N,M,L) :-  

5 range(1,M,R),

6 rnd_select(R,N,L).

 

注释行:

1. 引入谓词range/3

2. 引入谓词rnd_select/3

3. 

4. 从范围1到M范围取出N个随机元素放入列表L中

5. 产生1到M范围的自然数放在列表R中

6. 从列表R中取N个随机位置的元素

 

 

?- consult('p1_24.pl').

true.

 

?- lotto(6,49,L).

L = [34, 46, 44, 18, 40, 3] .

 

 

25、将指定列表中的元素打乱后随机排放

 

1  ensure_loaded(p1_23).

2

3  rnd_permu(L1,L2) :- 

4 length(L1,N),

5 rnd_select(L1,N,L2).

 

注释行:

1. 引入谓词rnd_select/3

2.

3. 将列表L1的元素重新随机排放到列表L2

4. 获取整个表的长度

5. 指定列表L1中的所有元素N重新随机排列到列表L2

 

?- consult('p1_25.pl').

true.

 

?- rnd_permu([a,b,c,d,e,f,1,2,3,4,5,6],L),write('L = '),write(L),nl.

L = [3,4,a,c,e,2,6,b,1,f,d,5]

L = [3, 4, a, c, e, 2, 6, b, 1|...] .

 

 

26、生成从列表的N个元素中选择的K个不同对象的组合

combination(K,L,C) :- C是从列表L中选择的K个不同元素的列表

 

1  combination(0,_,[]). 

2  combination(K,L,[X|Xs]) :-

3 K > 0,

4 el(X,L,R), 

5 K1 is K-1, 

6 combination(K1,R,Xs).

 

%分析下面谓词el/3的作用。

 

7  el(X,[X|L],L).

8  el(X,[_|L],R) :-

9 el(X,L,R).

 

注释行:

1. 0个组合的任何列表产生的列表都是空列表

2. 每个组合的个数为K,从列表L中取,组合好的表放到[X|Xs]

3. 确保K大于0

4. 获取元素X,获取剩余元素的列表R

5. 将 K 减 1的值赋给K1

6. 递归处理后续元素

7. 将列表[X|L]解析为元素X,和列表L

8. 忽略列表中[_|L]的’_’匿名元素

9. 继续递归处理后续元素

 

?- consult('p1_26.pl').

true.

 

?- combination(3,[a,b,c,d,e,f],L).

L = [a, b, c] ;

L = [a, b, d] ;

L = [a, b, e] ;

L = [a, b, f] .

 

 

27、将集合的元素分组为不相交的子集

将列表G的9个元素分配到列表G1,G2和G3中,这样列表G1,G2和G3分别包含2,3和4个元素

 

1  group3(G,G1,G2,G3) :-  

2 selectN(2,G,G1),

3 subtract(G,G1,R1), 

4 selectN(3,R1,G2),

5 subtract(R1,G2,R2),

6 selectN(4,R2,G3),

7 subtract(R2,G3,[]).

 

注释行:

1. 

2. 从列表G中获取有2个元素的列表G1

3. 从列表G获取除列表G1中的元素的剩余元素的列表R1

4. 从列表R1中获取有3个元素的列表G2

5. 从列表R1获取除列表G2中元素的剩余元素的列表R1

6. 从列表R2中获取有4个元素的列表G3

7. 从列表R2中获取除列表G3中元素的剩余元素的列表是空列表

 

 

返回所有可能的选择,但要避免排列;也就是说,在生成S = [a,b,c]之后,不要返回S = [b,a,c],依此类推。

 

9  selectN(0,_,[]) :- !.

 

10 selectN(N,L,[X|S]) :- 

11 N > 0,  

12 el(X,L,R),

13 N1 is N-1, 

14 selectN(N1,R,S). 

 

注释行:

8. 

9. 从任意列表中取0个元素,得到的列表一定是空列表

10.从列表L中取N个元素,将得到的元素放到列表[X|S]中(调用一次取一个元素)

11.确保N大于0

12. 将元素X和表R从L中解析出来

13.将N减1后把值赋给N1

14.递归继续处理后面的元素

 

% Use el/3 from p1_26:

:- ensure_loaded(p1_26).

 

% el(X,[X|L],L).

% el(X,[_|L],R) :- el(X,L,R).

 

% subtract/3 是预定义谓词

 

将G的元素分布到组Gs中。组的大小在列表Ns中给出。

15 group([],[],[]).  

16 group(G,[N1|Ns],[G1|Gs]) :-  

17 selectN(N1,G,G1),      

18 subtract(G,G1,R),     

19 group(R,Ns,Gs).    

 

注释行:

15.空列表,按第二参数空列表分组后的列表任然是空列表

16.将列表G,按第2参数标识的数字分配成参数3列表的列表

17.从列表G中获取有N1个元素的列表G1

18.从列表G获取除列表G1中的元素的剩余元素的列表R

19. 继续递归处理剩余元素列表R

 

?- consult('p1_27.pl').

true.

 

?- group3([ 赵,钱,孙,李,周,吴,郑,王,张],G1,G2,G3).

G1 = [赵, 钱],

G2 = [孙, 李, 周],

G3 = [吴, 郑, 王, 张] ;

G1 = [赵, 钱],

G2 = [孙, 李, 吴],

G3 = [周, 郑, 王, 张] .

 

?- group([赵,钱,孙,李,周,吴,郑,王,张],[2,2,5],Gs).

Gs = [[赵, 钱], [孙, 李], [周, 吴, 郑, 王, 张]] ;

Gs = [[赵, 钱], [孙, 周], [李, 吴, 郑, 王, 张]] ;

Gs = [[赵, 钱], [孙, 吴], [李, 周, 郑, 王, 张]] .

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值