0

I have an array a and a new_elem.

  • If new_elem is smaller than any existing member in a, then it is not allowed to be added into a.
  • On the contrary, if new_elem is larger than any existing member in a, then it is allowed to be added into a, and those existing elements smaller than new_elem have to be kicked out.

I implemented this as follows.

a = [a new_elem]; % add in first
for idx = 1:1:numel(a)-1
    % new_elem < some existing member
    if a(idx) > new_elem
        a = a(1:end-1); % kick new_elem out
        break;
    % new_elem > some existing member    
    elseif a(idx) < new_elem
        a(a==a(idx)) = []; % kick that exisiting member out
    end
end

The snippet works when new_elem is smaller, e.g.,

new_elem = 4;
a = [5 5 5 5 5];

It fails with the error Index exceeds matrix dimensions. in the other cases, e.g.,

new_elem = 6;
a = [5 5 5 5 5];

I understand that the problem is once we kick out an existing element, the size of a changes, and hence, we will have trouble indexing the final element, since numel(a) has been evaluated before the loop starts.

How could I fix it?

P.S.: This is a simplified version of my problem and actually involves a lot more. So please kindly do not subversively modify the algorithm.

2 Answers 2

1

Why not just get a list/array of all elements in a that are less than new_elem and make your decision based on that, avoiding loops altogether?

% get a list of all indices of elements in a that are less than new_elem
minIdcs = find(a<new_elem);

% if the length of this list is less than the length of a, then there is at
% least one element in a that is greater than new_elem - so only add new_elem
% if the lengths are identical
if length(minIdcs) == length(a)
    % remove all elements of a that are less than new_elem
    a(minIdcs) = [];

    % now add new_elem to a
    a = [a new_elem];
end

This works but I am not sure if it compatible with what you intended as your code is dependent upon the order of the elements in a: new_elem may be smaller than at least one element in a, but that element may not be encountered for several iterations of the loop, so other elements of a might be removed before we make the decision that new_elem should not be added.

If order is important, then you could use a while loop instead

a = [a new_elem]; % add in first
idx = 1;
n   = length(a);
while idx < n
    % new_elem < some existing member
    if a(idx) > new_elem
        a = a(1:end-1); % kick new_elem out
        break;
    % new_elem > some existing member    
    elseif a(idx) < new_elem
        a(idx) = []; % kick that exisiting member out
        n = n-1;
    else
        idx=idx+1;
    end
end

The above is very similar to what you have - we just need to keep track of the number of elements in the list (which is adjusted whenever we remove an element) and we need to increment the index idx only when we don't remove an element. And rather than removing all elements that are less than new_elem in one-shot, we handle them on a case-by-case basis (so a(idx) = []; rather than a(a==a(idx)) = [];).

Sign up to request clarification or add additional context in comments.

1 Comment

The slight modifications upon my extant algorithm works perfectly. Thanks a lot!
0

Just this simple code should do what you want:

if new_elem > min(a)
a = [new_elem a(find(new_elem < a))]
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.