I'd like to have a Prolog predicate that can replace an element in a list at a specified index.
Example:
% replace(+List,+Index,+Value,-NewList).
?- L=[a,b,c,d], replace(L,1,z,L2).
L2 = [a,z,c,d]
I don't know how to do this. Thanks for your help! Loïc.
I'll give you the base case, I think you should be able to do the recursive case with ease:
edit:
Now that the op has solved it, I'll add the recursive case:
edit2:
This should return the original list in an out of bounds situation as @GeorgeConstanza asks in the comments:
It's basically taking advantage of the cut operator to not get to the third fallback clause if there's a good in-bounds replacement.
Another way I came up with, which I think is correct (?). I don't know about the runtime complexity.
Usage:
The code presented in this previous answer is quite versatile—thanks to clpfd.
Is there a downside? Yes, there is a downside: Inefficiency!
In this answer, we improve performance and preserve versatility.
We proceed like this previous answer did when it defined the predicate
fd_length/2
:So... has it gotten any faster?
OK, it is faster. But is it still versatile?
Looks alright to me!
Really, nobody should ever do this with plain lists of any considerable length IMO, as each update will take up
O(n)
new space. Direct set_once/update viasetarg/nb_setarg
will take up0
new space, and with binary tree representation of lists,O(log(n))
new space. The replacements could also be held in a separate dictionary, itself maintained as a tree (as it needs to grow). A chunked list (as in here) could hold big chunks in a tree, each a fixed-sized compound term directly settable/updatable throughsetarg/nb_setarg
, and add new chunks into the tree as needed.Even without the update, just accessing plain lists is hopelessly slow,
O(n)
time, turning any algorithm quadratic in a jiffy. Lists are only good really short, or as a homework exercise.ok clearly the replace using recursion by @fortran is the the way to go. but is this too crazy/slow to actually use?
Basically you make a blank array of size Idx and bind it to the input list. then discard the item after that and bind the two lists together with the replacement element sandwiched in.
this can be simplified further if you are OK failing if you try to set idx N (indexing from 0) of an N element list.
The answer from fortran it's ok, but in SWI-Prolog structs have unlimited arity, so this should work:
but, to my surprise:
My first attempt (with K=10000000) killed the process! So, to my dislike, attempting to gain some performance, I end up filling a bug report to SWI-Prolog mailing list...
EDIT: After the post to SWI-Prolog mailing list, and the (fast!) correction, I have rebuilt, and here is the version accounting for a hint on memory usage (now it's all ISO standard code!). Due to the unusual large values, a stack grow instruction is needed before:
Here is the updated procedure:
and the test:
The code it's faster, but please note the comment of Jan to my mail: