Sibbs Gambling
Sibbs Gambling

Reputation: 20355

MATLAB - Loop through a size-variant array?

I have an array a and a new_elem.

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.

Upvotes: 0

Views: 79

Answers (2)

vrleboss
vrleboss

Reputation: 471

Just this simple code should do what you want:

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

Upvotes: 0

Geoff
Geoff

Reputation: 1603

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)) = [];).

Upvotes: 1

Related Questions