Prolog:替换指定索引处的列表中的元素

Loï*_*ier 16 list prolog

我想要一个Prolog谓词,它可以替换指定索引处的列表中的元素.

例:

% replace(+List,+Index,+Value,-NewList).
?- L=[a,b,c,d], replace(L,1,z,L2).
L2 = [a,z,c,d]
Run Code Online (Sandbox Code Playgroud)

我不知道该怎么做.谢谢你的帮助!卢瓦克.

for*_*ran 13

我会给你一个基本案例,我认为你应该能够轻松地做递归案例:

replace([_|T], 0, X, [X|T]).
Run Code Online (Sandbox Code Playgroud)

编辑:

现在op解决了它,我将添加递归的情况:

replace([H|T], I, X, [H|R]):- I > 0, I1 is I-1, replace(T, I1, X, R).
Run Code Online (Sandbox Code Playgroud)

EDIT2:

这应该在一个超出范围的情况下返回原始列表,因为@GeorgeConstanza在评论中要求:

replace([_|T], 0, X, [X|T]).
replace([H|T], I, X, [H|R]):- I > -1, NI is I-1, replace(T, NI, X, R), !.
replace(L, _, _, L).
Run Code Online (Sandbox Code Playgroud)

如果有一个良好的入境替换,它基本上利用了cut操作符来获得第三个回退子句.

  • `替换([_ | T],0,X,[X | T]).替换([H | T],I,X,[H | R]): - I1是I-1,替换(T,I1,X,R).谢谢:). (4认同)
  • 请在递归规则中添加"I> 0". (2认同)

小智 6

我想出的另一种方法,我认为是正确的(?)。我不知道运行时的复杂性。

replace(I, L, E, K) :-
  nth0(I, L, _, R),
  nth0(I, K, E, R).
Run Code Online (Sandbox Code Playgroud)

用法:

?- replace(2, [1, 2, 3, 4, 5], 10, X).
X = [1, 2, 10, 4, 5].
Run Code Online (Sandbox Code Playgroud)


Cap*_*liC 5

来自fortran的答案没关系,但在SWI-Prolog结构中有无限的arity,所以这应该工作:

replace([_|T], 0, X, [X|T]).
replace([H|T], I, X, [H|R]) :-
    I > 0,
    I1 is I - 1,
    replace(T, I1, X, R).

replace1(L, I, X, R) :-
    Dummy =.. [dummy|L],
    J is I + 1,
    nb_setarg(J, Dummy, X),
    Dummy =.. [dummy|R].

tr(Method, K) :-
    length(L, K),
    K1 is K - 1,
    time(call(Method, L, K1, test, R)),
    assertion(nth1(K, R, test)).
Run Code Online (Sandbox Code Playgroud)

但令我惊讶的是:

?- % /home/carlo/prolog/replace.pl compiled 0,00 sec, 2,280 bytes
?- tr(replace,2000000).
% 3,999,999 inferences, 2,123 CPU in 2,128 seconds (100% CPU, 1884446 Lips)
true .

?- tr(replace1,2000000).
% 5 inferences, 1,410 CPU in 1,414 seconds (100% CPU, 4 Lips)
true.

?- tr(replace,4000000).
% 7,999,999 inferences, 3,510 CPU in 3,520 seconds (100% CPU, 2279267 Lips)
true .

?- tr(replace1,4000000).
% 5 inferences, 2,825 CPU in 2,833 seconds (100% CPU, 2 Lips)
true.

?- tr(replace,5000000).
% 9,999,999 inferences, 3,144 CPU in 3,153 seconds (100% CPU, 3180971 Lips)
true .

?- tr(replace1,5000000).
% 5 inferences, 4,476 CPU in 4,486 seconds (100% CPU, 1 Lips)
ERROR: =../2: Arguments are not sufficiently instantiated
^  Exception: (9) setup_call_catcher_cleanup(system:true, prolog_statistics:catch(user:call(replace1, [_G1, _G4, _G7, _G10|...], 4999999, test, _G15000005), _G15000021, (report(t(1324124267.2924964, 18.892632697, 28490132), 10), throw(_G15000021))), _G15000145, prolog_statistics: (_G15000032=true)) ? abort
% Execution Aborted
Run Code Online (Sandbox Code Playgroud)

我的第一次尝试(K = 10000000)杀死了这个过程!所以,对于我的厌恶,试图获得一些表现,我最终填写了一份错误报告给SWI-Prolog邮件列表......

编辑:在发布到SWI-Prolog邮件列表和(快速!)更正之后,我已经重建了,这里是版本会计用于内存使用的提示(现在它是所有ISO标准代码!).由于不寻常的大值,在以下情况之前需要堆栈增长指令:

?- prolog_stack_property(global,limit(L)), N is L*2, set_prolog_stack(global,limit(N)).
N = 536870912.
Run Code Online (Sandbox Code Playgroud)

这是更新的程序:

replace2(L, I, X, R) :-
    Dummy =.. [dummy|L],
    J is I + 1,
    setarg(J, Dummy, X),
    Dummy =.. [dummy|R].
Run Code Online (Sandbox Code Playgroud)

和测试:

?- tr(replace,10000000).
% 19,999,999 inferences, 5.695 CPU in 5.719 seconds (100% CPU, 3511942 Lips)
true .

?- tr(replace2,10000000).
% 5 inferences, 2.564 CPU in 2.571 seconds (100% CPU, 2 Lips)
true.
Run Code Online (Sandbox Code Playgroud)

代码更快,但请注意Jan对我邮件的评论:

归结为= ..(+, - )中的错误处理.固定.顺便说一下,我认为这是完成这项工作的可怕方式.即使你想这样做,也只需使用setarg/3而不是nb_setarg/3.后者应该是最后的手段.此方法使用更多内存,因为它需要巨大的术语和列表.最后,函子(名称/ arity对)目前没有回收,所以你为每个替换列表创建一个这样的对象,其长度从未使用过.