所以,假设我有列表[1,2,3,4,5]
,我希望从此列表中获取12345
。
这是我写的代码
l_to_n(L, N) :-
reverse(L ,P),
list_to_n(P,0,N).
list_to_n([H|T], C, N) :-
C1 is C + 1,
list_to_n(T, C1, P),
N is H*(10**C) + P.
list_to_n([], _,0).
这是我找到的东西
l_to_n(List, N) :-
add_zero(List,Num),
name(N,Num).
add_zero([X|Tail1],[Y|Tail2]) :-
!,
Y is X+48,
add_zero(Tail1,Tail2).
add_zero([],[]) :-
!.
哪一个更快/更好地用于大型列表?
答案 0 :(得分:3)
这两个程序无法比较:第一个计算数字,第二个计算原子。第二个显然更简单,因此可能会更有效...如果你有一个内置转换原子到整数,当然......
第一个可以优化,而不是乘法和取幂,乘以10,得到幂,并且备用10**C
。
在SWI-Prolog中,atomic_list_concat/2
可以取代第二个......
答案 1 :(得分:1)
我认为两种方式都有点 hacky :首先你首先反转你的列表,这需要 O(n)时间,更重要的是需要额外的 O(n)内存用于存储新列表。然后在不需要尾递归的情况下执行递归调用,同时需要跟踪当前位置并执行指数运算。这可以进行优化。
如果我理解第二个,你基本上要做的是将数字列表转换为ASCII字符列表。然后你希望name能够进行有效的解析。
我提出以下谓词:
l_to_n(L,N) :-
l_to_n(L,0,N).
l_to_n([H|T],A,N) :-
!,
B is A*10+H,
l_to_n(T,B,N).
l_to_n(_,N,N).
它使用累加器A
。对于列表中的每个元素,累加器乘以10
,并将H
(该数字)添加到累加器。接下来,在列表的尾部进行尾递归。如果使用智能编译器/解释器,尾递归将阻止构建 O(n)调用堆栈。这可能很有用,因为您需要返回结果并撤消调用堆栈会导致额外的计算开销。
然而,这个谓词只能在一个方向上工作:数字列表。
<强>演示强>:
?- l_to_n([1,4,2,5],N).
N = 1425.
?- l_to_n([1,2,3,4,5],N).
N = 12345.