SWI Prolog Array Retrive [Index and Element] - arrays

I'm trying to program an array retrieval in swi-prolog. With the current code printed below I can retrieve the element at the given index but I also want to be able to retrieve the index[es] of a given element.
aget([_|X],Y,Z) :- Y \= 0, Y2 is (Y-1), aget(X,Y2,Z).
aget([W|_],Y,Z) :- Y = 0, Z is W.
Example 1: aget([9,8,7,6,5],1,N) {Retrieve the element 8 at index 1}
output: N = 9. {Correct}
Example 2: aget([9,8,7,6,5],N,7) {retrieve the index 2 for Element 7}
output: false {incorrect}
The way I understood it was that swi-prolog would work in this way with little no additional programing. So clearly I'm doing something wrong. If you could point me in the right direction or tell me what I'm doing wrong, I would greatly appreciate it.

Your code it's too procedural, and the second clause it's plainly wrong, working only for numbers.
The functionality you're looking for is implemented by nth0/3. In SWI-Prolog you can see the optimized source with ?- edit(nth0). An alternative implementation has been discussed here on SO (here my answer).
Note that Prolog doesn't have arrays, but lists. When an algorithm can be rephrased to avoid indexing, then we should do.

If you represent arrays as compounds, you can also use the ISO standard predicate arg/3 to access an array element. Here is an example run:
?- X = array(11,33,44,77), arg(2,X,Y).
X = array(11, 33, 44, 77),
Y = 33.
The advantage over lists is that the compound access needs O(1) time and whereas the list access needs O(n) time, where n is the length of the array.

Related

Find indices of value in array - IDL

I am learning IDL through some inherited code. In other languages (python, MATLAB), it is easy to find the indices associated with a value of interest in an array. However, I cannot seem to find any simple function or method to do this in IDL. For example:
A = [55, 6, 762, 35, 155, 1, 867, 35]
I know that the value 155 is in A, but I am interested in its location [x,y]. How can I easily access this information?
The only thing I can think of that is similar is finding a MAX value within an array.
B = max(A,location)
where the second argument (location) gives the index of the maximum value in A. However, I want to be able to do this with any value, not just max.
I am aware of the VALUE_LOCATE function, but that requires the array to be monotonic which is not the case here.
I have tried using WHERE and ARRAY_INDICES, among other things, but I don't think I am using them correctly (or they just don't do what I am asking for).
Thank you.
Of course, I figured it out right after posting this. Using the WHERE function solved the problem. If anyone searches for this in the future:
C = where(A eq desired_value)
You can keep track of the indices in the original array then use VALUE_LOCATE in the following way.
b = LINDGEN(N_ELEMENTS(a))
s = SORT(a)
c = b[s]
d = a[s]
Now just define your search value(s), say, as the variable v then you can do the following:
v = 155
i = VALUE_LOCATE(d,v) ;; index of sorted array
j = c[i[0]] ;; index of original, unsorted array
Then you can check your results by doing:
PRINT,';; ',a[j[0]],d[i[0]]
;; 155 155
The only annoying caveat of VALUE_LOCATE is that if the array a has any NaNs in it, the search will fail or return bad values so be careful of that.
If you know the value for which you are searching is an integer, then using WHERE will also work, for example:
good = WHERE(a EQ v[0],gd)
PRINT,';; ',a[good[0]]
;; 155
The caveat with using WHERE is if you only know the approximate search value and the array contains single- or double-precision floating point values. Sometimes your search will turn up null because you don't have the exact match.

Finding values of A and B from an array so that addition or subtraction equals to 40

Recently in an interview i was asked this question.
Given:
a + or - b = 40 // You can choose any one operator + or -
[list of any numbers in an array]
Explain how will you choose numbers for A and B from an given array to make the result 40 ?
My Answer:
Consider 1st element of array as A, now iterate through array from start to find possible values of B while this process fetch each element from array, sum up with A and compare it with 40.
But he was not happy.
Any other approaches ?
Sorting would definitely help you get the solution your interviewer has looked for:
First, sort the array. Should take about O(nlogn).
Now put 2 pointers, i and j. i starts at the beginning of the array, and j starts at the end.
Compare the 2 values (that i and j point to) to 40. If the result is bigger than 40, j moves to the left. If the result is smaller than 40, i moves to the right. You will keep doing this until having two values with the sum of 40.
If not found yet, do the same thing the other way around, for the subtraction of both values, to get 40.
The whole solution takes only O(nlogn) and is very elegant.
Good Luck!

Making use of binary search algorithm

I'm more interested in the thought process than in the code itself. I'm supposed to find the number of v[i] components in a sorted array such that x < v[i] < y, where x and y are sent as input from the keyboard.
I'm supposed to solve this efficiently using a modified binary search instead of a regular search through the vector.
My problem is that I can't visualize how to implement a binary search in this case, the method just doesn't seem fit to me.
Any thoughts ?
You could do a binary search in the array for x and y. Then you could subtract the index of x from the index of y to get how many items are between them.
You'd actually have to subtract 1 from that result since you are using strictly less-than.
For example, say you have an array:
[3, 6, 8, 10, 14, 39, 41, 100]
Let x=8 and y = 39.
The index of x is 2 and the index of y is 5.
5-2 = 3
3-1 = 2
If x and y are allowed to be values that are not contained in your array, you can still follow the same approach. Search for x and if it is not found, use the index of the element that is just larger than x. Likewise for the index of the element that is just smaller than y.
Supposing the original array v is sorted, just follow those steps:
Use binary search to locate value x in the array - if it's not there (the lower and upper bounds in binary search meet), get the index of closest higher value
Do the same for the y value, get the index of closest lower value if it's not this time
Find out how many items are in between (by subtracting indices and adding 1)
Here's a great article if you're interested: Binary Search
Depending on the values of x and y, if they're the lower and upper limits respectively of numbers within the array, it's as simple as applying a general BS algorithm with those limits in place rather than the general first and last element of the array.
Drawing it up on paper will help.

Dynamic Programming Problem.. Array Partitioning..

The question says,
That given an array of size n, we have to output/partition the array into subsets which sum to N.
For E,g,
I/p arr{2,4,5,7}, n=4, N(sum) = 7(given)
O/p = {2,5}, {7}
I saw similar kind of problem/explanation in the url Dynamic Programming3
And I have the following queries in the pdf:-
How could we find the subsets which sum to N, as the logic only tells whether the subset exist or not?
Also, if we change the question a bit, can we find two subsets which has equal average using the same ideology?
Can anybody thrown some light on this Dynamic Programming problem.. :)
Thanks in Advance..
You can try to process recursively:
Given a SORTED array X={x1 ... xn} xi !=0 and an intger N.
First find all the possibilities "made" with just one element:
here if N=xp, eliminate all xi s.t i>=p
second find all the possibilities made with 2 elements:
{ (x1,x2) .... (xp-2,xp-1)}
Sort by sum and elminate all the sums >=N
and you had the rules: xi cannot go with xj when xi+xj >= N
Third with 3 elments:
You create all the part that respect the above rule.
And idem step 2
etc...
Example:
X={1,2,4,7,9,10} N=9
step one:
{9}
X'={1,2,4,7,9}
step 2: cannot chose 9 and 10
X={(1,2) (1,4) (2,4) (1,7) (2,7) (4,7)}
{2,7}
X'={(1,2) (1,4) (2,4) (1,7)}
step 3: 4 and 2 cannot go with 7:
X={(1,2,4)}
no sol
{9} {2,7} are the only solutions
This diminishes the total number of comparaison (that would be 2^n = 2^6=64) you only did : 12 comparaisons
hope it helps
Unfortunately, this is a very difficult problem. Even determining if there exists a single subset summing to your target value is NP-Complete.
If the problem is more restricted, you might be able to find a good algorithm. For example:
Do the subsets have to be contiguous?
Can you ignore subsets with more than K values?
Are the array values guaranteed to be positive?
Are the array values guaranteed to be distinct? What about differing from the other values by at least some constant factor?
Is there some bound on the difference between the smallest and largest value?
The proposed algorithm stores only a single bit of information in the temporary array T[N], namely whether it's reachable at all. Obviously, you can store more information at each index [N], such as the values C[i] used to get there. (It's a variation of the "Dealing with Unlimited Copies" chapter in the PDF)

Finding whether a value is equal to the value of any array element in MATLAB

Can anyone tell me if there is a way (in MATLAB) to check whether a certain value is equal to any of the values stored within another array?
The way I intend to use it is to check whether an element index in one matrix is equal to the values stored in another array (where the stored values are the indices of the elements which meet a certain criteria).
So, if the indices of the elements which meet the criteria are stored in the matrix below:
criteriacheck = [3 5 6 8 20];
Going through the main array (called array) and checking if the index matches:
for i = 1:numel(array)
if i == 'Any value stored in criteriacheck'
%# "Do this"
end
end
Does anyone have an idea of how I might go about this?
The excellent answer previously given by #woodchips applies here as well:
Many ways to do this. ismember is the first that comes to mind, since it is a set membership action you wish to take. Thus
X = primes(20);
ismember([15 17],X)
ans =
0 1
Since 15 is not prime, but 17 is, ismember has done its job well here.
Of course, find (or any) will also work. But these are not vectorized in the sense that ismember was. We can test to see if 15 is in the set represented by X, but to test both of those numbers will take a loop, or successive tests.
~isempty(find(X == 15))
~isempty(find(X == 17))
or,
any(X == 15)
any(X == 17)
Finally, I would point out that tests for exact values are dangerous if the numbers may be true floats. Tests against integer values as I have shown are easy. But tests against floating point numbers should usually employ a tolerance.
tol = 10*eps;
any(abs(X - 3.1415926535897932384) <= tol)
you could use the find command
if (~isempty(find(criteriacheck == i)))
% do something
end
Note: Although this answer doesn't address the question in the title, it does address a more fundamental issue with how you are designing your for loop (the solution of which negates having to do what you are asking in the title). ;)
Based on the for loop you've written, your array criteriacheck appears to be a set of indices into array, and for each of these indexed elements you want to do some computation. If this is so, here's an alternative way for you to design your for loop:
for i = criteriacheck
%# Do something with array(i)
end
This will loop over all the values in criteriacheck, setting i to each subsequent value (i.e. 3, 5, 6, 8, and 20 in your example). This is more compact and efficient than looping over each element of array and checking if the index is in criteriacheck.
NOTE: As Jonas points out, you want to make sure criteriacheck is a row vector for the for loop to function properly. You can form any matrix into a row vector by following it with the (:)' syntax, which reshapes it into a column vector and then transposes it into a row vector:
for i = criteriacheck(:)'
...
The original question "Can anyone tell me if there is a way (in MATLAB) to check whether a certain value is equal to any of the values stored within another array?" can be solved without any loop.
Just use the setdiff function.
I think the INTERSECT function is what you are looking for.
C = intersect(A,B) returns the values common to both A and B. The
values of C are in sorted order.
http://www.mathworks.de/de/help/matlab/ref/intersect.html
The question if i == 'Any value stored in criteriacheck can also be answered this way if you consider i a trivial matrix. However, you are proably better off with any(i==criteriacheck)

Resources