# Maybe add `vectorial_nth0/3`, `vectorial_replace/4` to library(lists)?

I did some practice exercise on a problem at Rosetta Code. This code is likely heavier than it needs to be:

Sort Disjoint Sublist

Given a list of values and a set of integer indices into that value list, the task is to sort
the values at the given indices, but preserving the values at indices outside the set of those
to be sorted.

Make your example work with the following list of values and set of indices: ``

``````  values: [7, 6, 5, 4, 3, 2, 1, 0]
indices: {6, 1, 7}
``````

Where the correct result would be:

``````[7, 0, 5, 4, 3, 2, 1, 6]
``````

Rosettacode is a bit disshelved in that it needs a better filing principle than a wiki, online code-exercising test harnesses and a code-markup-and-commenting system. Some people also write â€ścoding golfâ€ť exercises which misses the point.

Anyway, the above has made me notice that one might want to consider the following additions to `library(list)`:

`vectorial_nth0(IndexList,List,Elements)`

The integer indexes listed in `IndexList` (not necessarily ordered or disjoint) indicate which elements from `List` to unify with elements from `Elements`, in order of appearance of the pairs of elements from `IndexList` and `Elements`. `IndexList` and `Elements` must be of the same length.

For example:

`vectorial_nth0([1,0,1,3,2],List,[A,B,C,D,E])`

performs:

``````nth_0(1,List,A),
nth_0(0,List,B),
nth_0(1,List,C),
nth_0(3,List,D),
nth_0(2,List,E).
``````

Heroic programming could enlargen semantics to accept nonground elements in `IndexList`.

Similarly:

`vectorial_replace(IndexList,Elements,ListIn,ListOut)`

The integer indexes listed in `IndexList` (necessarily disjoint but necessarily ordered) indicate which elements from `ListIn` to replace by element from `Elements` (which could be fresh variables), in order of appearance of the pairs of elements from `IndexList` and `Elements`, giving `ListOut`. `IndexList` and `Elements` must be of the same length.

One could then write things like this solution in R

``````values=c(7,6,5,4,3,2,1,0)
indices=c(7,2,8)
values[sort(indices)]=sort(values[indices])
print(values)
``````
``````7 0 5 4 3 2 1 6
``````

Similar to D, Groovy, (maybe APL, I canâ€™t read it), Perl & Raku. The various LISPs still are weirdly verbose and opaque.

Note that you can also use:

``````   ?- maplist([Index,Element]>>nth0(Index,[a,b,c,d],Element), [1,0,1,3,2], [A,B,C,D,E]).
A = C, C = b,
B = a,
D = d,
E = c.``````
1 Like

I have not tried this but have you considered using arg/3?

A no, thatâ€™s for deconstructing terms. I just need parallel list access.

After a rewrite this morning, I have:

``````% ===
% Main predicate
% ===

sort_disjoint_sublist(Values,Indexes,ValuesSorted) :-
sort(Indexes,IndexesSorted),
insert_fresh_vars_by_splintering(IndexesSorted,Values,FreshVars,ValsToSort,ValuesFreshened),
msort(ValsToSort,ValsSorted),  % this is the "sorting of values"
% The next two lines could be left out with suitable naming,
% but they make explicit what happens:
FreshVars = ValsSorted,         % fresh variables are unified with sorted variables
ValuesSorted = ValuesFreshened. % ValuesFreshend is automatically the sought output

% ===
% Helpers
% ===

insert_fresh_vars_by_splintering([I|Is],Values,[Fresh|FreshVars],[ValAtI|ValsToSort],ValsFreshyFinal) :-
splinter(Values,I,ValAtI,ValsFront,ValsBack),         % splinter  Values  --> ValsFront + ValAtI + ValsBack
append([ValsFront,[Fresh],ValsBack],ValsFreshyNext),  % recompose ValsFront + Fresh + ValsBack --> ValuesFreshyNext
insert_fresh_vars_by_splintering(Is,ValsFreshyNext,FreshVars,ValsToSort,ValsFreshyFinal).

insert_fresh_vars_by_splintering([],V,[],[],V).

% "splinter" a list into a frontlist, the element at position N and a backlist

splinter(List, N, Elem, Front, Back) :-
length(Front, N),
append(Front, [Elem|Back], List).
``````

This works perfectly well, but itâ€™s hard to read.

It occurs to me that one of the reasons it is hard to read is that everyone knows what append is but nobody knows what splinter is. There is not enough â€śvocabularyâ€ť. Said vocabulary comes implicitly in expressions like the R expression

``````values[sort(indices)]=sort(values[indices])
``````

Although it takes a bit to prove to oneself that this does what it should.

Ok, here is the code for `vector_nth0(Indexes,List,Elements)`:

The code is less interesting than the test cases.

To my great amazement, this did search for fitting index vectors â€śout of the boxâ€ť because `nth0/3` is already doing search. Still took a bit to test this.

https://www.swi-prolog.org/pldoc/doc_for?object=same_length/2

I didnâ€™t know that one. OTOH, I need to fail if both variables-intended-to-be-lists are fresh, but `same_length/2` merrily generates away in that case.