Reputation: 14103
Say I have a List [1,2,4,5], I would like to have a predicate that returns 3 as the missing element. You can assuming that the input list is always sorted sequentially.
My solution so far:
% missing_number/2 (ListToBeChecked, ListToBeCompared, MissingNum)
missing_number([], [], []) :- !.
missing_number([Head | Tail], [Head | Rest], Number) :-
missing_number(Tail, Rest, Number).
missing_number(_, [X | _], [X | Node]) :-
missing_number(_, _, Number), !.
Upvotes: 2
Views: 732
Reputation: 1
Please see below: The implementation is in JavaScript. But the algorithm can be converted. I hope this helps! The assumption is that the list is ascending and is an arithmetric series - n, n+1, n+2... Additionally, the list can start anywhere, not just at 0
function getMissingNum() {
var start = Math.floor(Math.random() * 150) / 1;
var nElem = Math.floor(Math.random() * 20) / 1;
var set = [];
var rand = Math.floor(Math.random() * nElem) + start / 1;
for (var i = start; i <= start + nElem; i++) {
//skip one number randomly
if (i == rand) continue;
set.push(i);
}
var sum = 0;
for (var i = 0; i < set.length; i++) {
sum += set[i];
}
// SEE HERE:
// Total = N * (N + 1) / 2
var max = set[set.length - 1];
var min = set[0];// - 1;
var actual = (((max * (max + 1)) / 2));
var excluded = (((min * (min + 1)) / 2));
var missing = actual - excluded - sum + start;
if (min > start) {
missing = missing + min;
}
return {
missing: missing,
min: min,
max: max,
actual: actual,
excluded: excluded,
rand: rand,
start: start,
nElem: nElem
}
}
var results = [];
for (var i = 0; i < 100; i++) {
var result = getMissingNum();
if (result.rand != result.missing) {
results.push(result);
}
}
Upvotes: 0
Reputation: 23
it doesn't work for unsorted lists
missing([], []).
missing([H|T], R) :- missing([H|T], H, R).
missing([], _I, []).
missing([H|T], I, [I|R]) :-
H =\= I,
!,
NextI is I + 1,
missing([H|T], NextI, R).
missing([_|T], I, R) :-
NextI is I + 1,
missing(T, NextI, R).
Upvotes: 1
Reputation: 60034
The paradigmatic predicate append/3 many times can help in duties involving lists: here suffice to check for consecutive elements that aren't successors:
missing(L, M) :-
append(_, [A,B|_], L),
\+ succ(A, B), succ(A, M).
Completed
To be able to fulfill gaps of length > 1, the solution ends up almost identical to the larsman one:
missing(L, M) :-
append(_, [A,B|_], L),
succ(A, S), succ(P, B), between(S, P, M).
succ/2 allows a more declarative approach, but it's noticeably slower than arithmetic.
Upvotes: 3
Reputation: 363777
Use between/3
to generate all numbers from min to max. Use memberchk/2
(or member/2
) to find the missing ones.
L = [1,2,4,5],
L = [M|_],
last(L, N),
between(M, N, I),
\+ memberchk(I, L).
Exercise for the reader: wrap this up in a predicate.
EDIT Efficient solution, by popular request:
missing([I,K|_], M) :-
I1 is I+1,
K1 is K-1,
between(I1, K1, M).
missing([_|Ns], M) :-
missing(Ns, M).
EDIT 2: More elegant version of the above, inspired by @chac, not necessarily very efficient:
missing(L,M) :- append(_, [I,J|_], L), I1 is I+1, J1 is J-1, between(I1,J1,M).
Upvotes: 4
Reputation: 7493
missing([], []).
missing([H|T], R) :- missing([H|T], H, R).
missing([], _I, []).
missing([H|T], I, [I|R]) :-
H =\= I,
!,
NextI is I + 1,
missing([H|T], NextI, R).
missing([_|T], I, R) :-
NextI is I + 1,
missing(T, NextI, R).
for the no helper predicate one.
Upvotes: 0