Reputation: 20355
I have an array a
and a new_elem
.
new_elem
is smaller than any existing member in a
, then it is not allowed to be added into a
.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.
Upvotes: 0
Views: 79
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
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