Is There Any Practical Difference Between Extraction and Deletion When Reducing a Vector?

By extraction, I mean
% x = x(indexkeep);
By deletion, I mean
% x(indexdelete) = []
Is there any practical difference between these two options (speed, memory management, other?) or is it just a matter of style?
If using numerical indexing, then I suppose it's best to just go with the starting point, e.g., if numerical indexdelete is what we have, then just go with deletion rather than taking the extra step of forming indexkeep for extraction? But if indexdelete is a logical, then converting to indexkeep is trivial if extraction is the better option.
Do locations of the elements to be extracted/deleted matter?
What if using end indexing?
% x = x(n:end); vs.
% x(1:n-1) = [];
As a side note, I came across this behavior that shows a practical difference when deleting/extracting from 2D arrays. Apparently deletion always returns a row vector, whereas extraction returns a row or column depending on the orientation of the index.
xx = rand(2,2);
x = xx; x([1,3]) = []
x = 1×2
0.5468 0.0755
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
x = xx; x([1,3]') = []
x = 1×2
0.5468 0.0755
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
x = xx; x = x([2,4])
x = 1×2
0.5468 0.0755
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
x = xx; x = x([2,4]') % returns a column
x = 2×1
0.5468 0.0755
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
x = xx; x([true,false,true,false]) = []
x = 1×2
0.5468 0.0755
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
x = xx; x([true,false,true,false]') = []
x = 1×2
0.5468 0.0755
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
x = xx; x = x(~[true,false,true,false])
x = 1×2
0.5468 0.0755
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
x = xx; x = x(~[true,false,true,false]') % returns a column
x = 2×1
0.5468 0.0755
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>

3 Comments

If I recall correctly, deletion will work in-place and extraction will not. So extraction will first create a new array of the smaller size and deletion will attempt to edit the original without creating a copy. However, I'm not sure this is true.
I also vaguely recall that Matlab handles the end index in a special way, making it faster than using the numerical last index.
Did you already try to come up with some code snippets to try to build a benchmark to observe the theoretical results?
I have not tried any benchmarks.
Also, I wonder if the class of x makes a difference, particularly for classes that use contiguous storage and those that don't.
Supposing delete is in place, wouldn't it still have to move data around, assuming contiguous storage?
format debug
a = 1:5
a =
Structure address = 79fb5a97f200 m = 1 n = 5 pr = 79fb297f27e0 1 2 3 4 5
a(5) = []
a =
Structure address = 79fb5afd50c0 m = 1 n = 4 pr = 79fb4e2a8f40 1 2 3 4
a = 1:5, a = a(1:4)
a =
Structure address = 79fb5a289a60 m = 1 n = 5 pr = 79fb288474a0 1 2 3 4 5
a =
Structure address = 79fb5a28abe0 m = 1 n = 4 pr = 79fb4e284d20 1 2 3 4
Shows both created new allocations; "pr" is the pointer to the real data location in memory.
While it may be physically possible to delete totally in memory, one can't control what MATLAB chooses to do in reallocation at the user level; it is possible with mex to simply change the metadata and not move anything, but one can't prevent it doing whatever it is going to do internally. Internally, the JIT optimizer will decide what is most efficient.

Sign in to comment.

 Accepted Answer

format long g
X = rand(1,10000);
to_delete_unsorted = randperm(width(X), 20);
to_delete_sorted = sort(to_delete_unsorted);
to_keep_sorted = setdiff(1:width(X), to_delete_sorted);
to_keep_unsorted = to_keep_sorted(randperm(length(to_keep_sorted)));
t1 = zeros(40,1);
t2 = t1;
t3 = t1;
t4 = t1;
t5 = t1;
t6 = t1;
t7 = t1;
for K = 1 : length(t1);
x1 = X;
t0 = tic;
x1(to_delete_unsorted) = [];
t1(K) = toc(t0);
x2 = X;
t0 = tic;
x2(to_delete_sorted) = [];
t2(K) = toc(t0);
x3 = X;
t0 = tic;
x3(1000:1019) = [];
t3(K) = toc(t0);
x4 = X;
t0 = tic;
x4(9982:10000) = [];
t4(K) = toc(t0);
x5 = X;
t0 = tic;
x5(9982:end) = [];
t5(K) = toc(t0);
x6 = X;
t0 = tic;
x6 = x6(to_keep_unsorted);
t6(K) = toc(t0);
x7 = X;
t0 = tic;
x7 = x7(to_keep_sorted);
t7(K) = toc(t0);
end
t1 = t1(2:end); t2 = t2(2:end); t3 = t3(2:end); t4 = t4(2:end);
t5 = t5(2:end); t6 = t6(2:end); t7 = t7(2:end);
plot( [t1, t2, t3, t4, t5, t6 t7] );
legend({'unsorted', 'sorted', 'middle', 'numeric end', 'end', 'keep unsorted', 'keep sorted'});
disp(mean([t1, t2, t3, t4, t5, t6, t7]).'*1000 + " ms")
"0.017231 ms" "0.015256 ms" "0.012462 ms" "0.0087436 ms" "0.0098205 ms" "0.023359 ms" "0.023026 ms"
Warning: Graphics acceleration hardware is unavailable. Graphics quality and performance might be diminished. See MATLAB System Requirements.
So, for small number of elements to delete, fastest is deletion of either N:end or N:(numeric value of end) (different runs swap those results.) Second fastest is the other of N:end or N:(numeric value of end). Third fastest is hard-coded numeric indices in the middle. Fourth fastest is deletion of sorted numeric scattered indices. Fifth fastest is hard-coded numeric indices in the middle. Sixth and seventh fastest are pretty much the same, being extraction of sorted or unsorted explicit elements.
In a number of runs, deletion by unsorted numeric indices was faster than deletion by sorted numeric indices.
Note: the peak here at offset 4 in the plots is a feature that occured for all runs of the code here on MATLAB Answers. Not just some of them: all of them. I am mystified.

11 Comments

Agggh, the plot doesn't show up !
It looks somewhat like this:
format long g
X = rand(1,10000).'; % use row vector instead of column
to_delete_unsorted = randperm(numel(X), 20);
to_delete_sorted = sort(to_delete_unsorted);
to_keep_sorted = setdiff(1:width(X), to_delete_sorted);
to_keep_unsorted = to_keep_sorted(randperm(length(to_keep_sorted)));
t1 = zeros(40,1);
t2 = t1;
t3 = t1;
t4 = t1;
t5 = t1;
t6 = t1;
t7 = t1;
for K = 1 : length(t1);
x1 = X;
t0 = tic;
x1(to_delete_unsorted) = [];
t1(K) = toc(t0);
x2 = X;
t0 = tic;
x2(to_delete_sorted) = [];
t2(K) = toc(t0);
x3 = X;
t0 = tic;
x3(1000:1019) = [];
t3(K) = toc(t0);
x4 = X;
t0 = tic;
x4(9982:10000) = [];
t4(K) = toc(t0);
x5 = X;
t0 = tic;
x5(9982:end) = [];
t5(K) = toc(t0);
x6 = X;
t0 = tic;
x6 = x6(to_keep_unsorted);
t6(K) = toc(t0);
x7 = X;
t0 = tic;
x7 = x7(to_keep_sorted);
t7(K) = toc(t0);
end
t1 = t1(2:end); t2 = t2(2:end); t3 = t3(2:end); t4 = t4(2:end);
t5 = t5(2:end); t6 = t6(2:end); t7 = t7(2:end);
plot( [t1, t2, t3, t4, t5, t6 t7] );
lgd={'unsorted', 'sorted', 'middle', 'numeric end', 'end', 'keep unsorted', 'keep sorted'};
legend(lgd);
disp(mean([t1, t2, t3, t4, t5, t6, t7]).'*1000 + " ms : "+string(lgd.'))
"0.016128 ms : unsorted" "0.014385 ms : sorted" "0.011692 ms : middle" "0.0089487 ms : numeric end" "0.0091795 ms : end" "0.0012308 ms : keep unsorted" "0.0010513 ms : keep sorted"
Converting the column vector to a row vector instead completely flips the results -- I hadn't noticed that orientation difference before but knew had to be something going on. The contiguous storage by column is backwards of the C/C++ internal memory layout and so ends up causing big hit in cache misses for large arrays; this would undoubtedly go away for smaller arrays.
I can't explain the plot showing here and not for you, Walter...and the anomalous behavior on iteration 4 is most peculiar, indeed. I wonder if it possibly indicates a higher level of JIT compilation occurs after a few iterations of a loop; I've seen conjectures of that nature elsewhere.
This shows the inherent issue behind why MATLAB defaults to row vectors despite being defined as column major. Its heritage and continued use of BLAS/LAPACK that were developed and optimized for Fortran column major orientation are fast; on the other hand, when MATLAB was rewritten in C/C++, the standard libraries against which it links are written on the assumption of C's row-major orientation and since even a 1D vector is internally a 2D array, the dimension propagation rules require computing the addressing as a 2D array and so indexing down a large column vector actually internally is addressing the first column of the long NX1 2D array and must compute that address from the 2D addressing which kills the JIT that can't recognize the linear contiguous memory it can when it's a row instead.
I opened a case about the odd peak on K = 5, but I have not had a response yet.
Besides the peak for the deletion cases, note that the average time drops for all after that point which bolsters the conjecture of JIT having a second level inside a loop after a number of iterations. One presumes the other occasional blips are OS memory and/or task switching artifacts.
format long g
X = rand(1,10000);
to_delete_unsorted = randperm(numel(X), 20);
to_delete_sorted = sort(to_delete_unsorted);
to_keep_sorted = setdiff(1:width(X), to_delete_sorted);
to_keep_unsorted = to_keep_sorted(randperm(length(to_keep_sorted)));
t1 = zeros(40,1);
t2 = t1;
t3 = t1;
t4 = t1;
t5 = t1;
t6 = t1;
t7 = t1;
for K = 1:length(t1);
x1 = X;
t0 = tic;
x1(to_delete_unsorted) = [];
t1(K) = toc(t0);
x2 = X;
t0 = tic;
x2(to_delete_sorted) = [];
t2(K) = toc(t0);
x3 = X;
t0 = tic;
x3(1000:1019) = [];
t3(K) = toc(t0);
x4 = X;
t0 = tic;
x4(9982:10000) = [];
t4(K) = toc(t0);
x5 = X;
t0 = tic;
x5(9982:end) = [];
t5(K) = toc(t0);
x6 = X;
t0 = tic;
x6 = x6(to_keep_unsorted);
t6(K) = toc(t0);
x7 = X;
t0 = tic;
x7 = x7(to_keep_sorted);
t7(K) = toc(t0);
end
t1 = t1(2:end); t2 = t2(2:end); t3 = t3(2:end); t4 = t4(2:end);
t5 = t5(2:end); t6 = t6(2:end); t7 = t7(2:end);
%subplot(2,1,1)
%plot( [t1, t2, t3, t4, t5, t6 t7] );
lgd={'unsorted', 'sorted', 'middle', 'numeric end', 'end', 'keep unsorted', 'keep sorted'};
%legend(lgd);
%title('Row Vector')
%disp(mean([t1, t2, t3, t4, t5, t6, t7]).'*1000 + " ms : "+string(lgd.'))
T(1,:)=mean([t1, t2, t3, t4, t5, t6, t7]).'*1000;
clearvars -except to_* lgd T
X=rand(10000,1);
to_delete_unsorted = randperm(numel(X), 20);
to_delete_sorted = sort(to_delete_unsorted);
to_keep_sorted = setdiff(1:width(X), to_delete_sorted);
to_keep_unsorted = to_keep_sorted(randperm(length(to_keep_sorted)));
t1 = zeros(40,1);
t2 = t1;
t3 = t1;
t4 = t1;
t5 = t1;
t6 = t1;
t7 = t1;
for K = 1 : length(t1);
x1 = X;
t0 = tic;
x1(to_delete_unsorted) = [];
t1(K) = toc(t0);
x2 = X;
t0 = tic;
x2(to_delete_sorted) = [];
t2(K) = toc(t0);
x3 = X;
t0 = tic;
x3(1000:1019) = [];
t3(K) = toc(t0);
x4 = X;
t0 = tic;
x4(9982:10000) = [];
t4(K) = toc(t0);
x5 = X;
t0 = tic;
x5(9982:end) = [];
t5(K) = toc(t0);
x6 = X;
t0 = tic;
x6 = x6(to_keep_unsorted);
t6(K) = toc(t0);
x7 = X;
t0 = tic;
x7 = x7(to_keep_sorted);
t7(K) = toc(t0);
end
t1 = t1(2:end); t2 = t2(2:end); t3 = t3(2:end); t4 = t4(2:end);
t5 = t5(2:end); t6 = t6(2:end); t7 = t7(2:end);
%subplot(2,1,2)
%plot( [t1, t2, t3, t4, t5, t6 t7] );
%legend(lgd);
%title('Column Vector')
T(2,:)=mean([t1, t2, t3, t4, t5, t6, t7]).'*1000;
x=categorical(lgd,lgd,'ordinal',1);
bar(x,T.','grouped')
legend('Row Vector','Column Vector','location','northwest')
I erred in the orientation before misreading the original orientation in @Walter Roberson's code; his original was a row vector, not a column. So, in fact, it is the column orientation internally that does outperform the row for the "Keep" operation. My bad, sorry...that does make more sense.
I did have to clear variables to get it to not produce essentially identical results; that I didn't quite follow; simply a loop with X=X.'; for the second iteration didn't change the timing results significantly; perhaps there's something going on I didn't catch with tic,toc, I'm not sure...
Note: revised to keep the middle N elements; previous version still used hard-coded 20 elements.
Row versus column are the same to within timing error for the case where the majority is to be kept (or deleted)
format long g
X = rand(1,10000);
NE = 9000;
to_delete_unsorted = randperm(numel(X), NE);
to_delete_sorted = sort(to_delete_unsorted);
to_keep_sorted = setdiff(1:width(X), to_delete_sorted);
to_keep_unsorted = to_keep_sorted(randperm(length(to_keep_sorted)));
t1 = zeros(40,1);
t2 = t1;
t3 = t1;
t4 = t1;
t5 = t1;
t6 = t1;
t7 = t1;
for K = 1:length(t1);
x1 = X;
t0 = tic;
x1(to_delete_unsorted) = [];
t1(K) = toc(t0);
x2 = X;
t0 = tic;
x2(to_delete_sorted) = [];
t2(K) = toc(t0);
x3 = X;
t0 = tic;
x3(500:500+NE-1) = [];
t3(K) = toc(t0);
x4 = X;
t0 = tic;
x4(10000-NE+1:10000) = [];
t4(K) = toc(t0);
x5 = X;
t0 = tic;
x5(10000-NE+1:end) = [];
t5(K) = toc(t0);
x6 = X;
t0 = tic;
x6 = x6(to_keep_unsorted);
t6(K) = toc(t0);
x7 = X;
t0 = tic;
x7 = x7(to_keep_sorted);
t7(K) = toc(t0);
end
t1 = t1(2:end); t2 = t2(2:end); t3 = t3(2:end); t4 = t4(2:end);
t5 = t5(2:end); t6 = t6(2:end); t7 = t7(2:end);
lgd={'unsorted', 'sorted', 'middle', 'numeric end', 'end', 'keep unsorted', 'keep sorted'};
T(1,:)=mean([t1, t2, t3, t4, t5, t6, t7]).'*1000;
clearvars -except to_* lgd T X NE
X=X.';
t1 = zeros(40,1);
t2 = t1;
t3 = t1;
t4 = t1;
t5 = t1;
t6 = t1;
t7 = t1;
for K = 1 : length(t1);
x1 = X;
t0 = tic;
x1(to_delete_unsorted) = [];
t1(K) = toc(t0);
x2 = X;
t0 = tic;
x2(to_delete_sorted) = [];
t2(K) = toc(t0);
x3 = X;
t0 = tic;
x3(500:500+NE-1) = [];
t3(K) = toc(t0);
x4 = X;
t0 = tic;
x4(10000-NE+1:10000) = [];
t4(K) = toc(t0);
x5 = X;
t0 = tic;
x5(10000-NE+1:end) = [];
t5(K) = toc(t0);
x6 = X;
t0 = tic;
x6 = x6(to_keep_unsorted);
t6(K) = toc(t0);
x7 = X;
t0 = tic;
x7 = x7(to_keep_sorted);
t7(K) = toc(t0);
end
t1 = t1(2:end); t2 = t2(2:end); t3 = t3(2:end); t4 = t4(2:end);
t5 = t5(2:end); t6 = t6(2:end); t7 = t7(2:end);
T(2,:)=mean([t1, t2, t3, t4, t5, t6, t7]).'*1000;
x=categorical(lgd,lgd,'ordinal',1);
bar(x,T.','grouped')
legend('Row Vector','Column Vector','location','northeast')
Yeah, that doesn't surprise me too much although "keep" is still much better. The tests here except for first and last pairs aren't comparative/relevant, though as they're still the initial much fewer elements being manipulated.
Don't suppose you looked to see if the K==4 spike still occurred?
I revised the post to handle the middle and end correctly; the previous version still had 20 elements hard-coded.
@Walter Roberson - "Note: revised to keep the middle N elements;..."
Hmmmm....that surprises me to now be so big a difference for t3, t4, t5 vis a vis t1, t2 based on whether is variable vector or numeric. Wonder if orientation of the vector would matter?
X = rand(1,10000);
NE = 9000;
to_delete_unsorted = randperm(numel(X), NE);
size(to_delete_unsorted)
ans = 1×2
1 9000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
is a row, not column vector to also have to address.
Well, the following shows that doesn't make any difference -- can't explain that, either, other than being related to the problem of dynamic validation that the indices in the variable are valid as could be GLOBAL or other ways to be changed whereas the numeric vectors are, at least, immutable even if must check for being valid first.
format long g
X = rand(1,10000);
NE = 9000;
to_delete_unsorted = randperm(numel(X), NE).';
to_delete_sorted = sort(to_delete_unsorted);
disp([height(to_delete_unsorted) height(to_delete_unsorted)])
9000 9000
to_keep_sorted = setdiff(1:width(X), to_delete_sorted);
to_keep_unsorted = to_keep_sorted(randperm(length(to_keep_sorted)));
t1 = zeros(40,1);
t2 = t1;
t3 = t1;
t4 = t1;
t5 = t1;
t6 = t1;
t7 = t1;
for K = 1:length(t1);
x1 = X;
t0 = tic;
x1(to_delete_unsorted) = [];
t1(K) = toc(t0);
x2 = X;
t0 = tic;
x2(to_delete_sorted) = [];
t2(K) = toc(t0);
x3 = X;
t0 = tic;
x3(500:500+NE-1) = [];
t3(K) = toc(t0);
x4 = X;
t0 = tic;
x4(10000-NE+1:10000) = [];
t4(K) = toc(t0);
x5 = X;
t0 = tic;
x5(10000-NE+1:end) = [];
t5(K) = toc(t0);
x6 = X;
t0 = tic;
x6 = x6(to_keep_unsorted);
t6(K) = toc(t0);
x7 = X;
t0 = tic;
x7 = x7(to_keep_sorted);
t7(K) = toc(t0);
end
t1 = t1(2:end); t2 = t2(2:end); t3 = t3(2:end); t4 = t4(2:end);
t5 = t5(2:end); t6 = t6(2:end); t7 = t7(2:end);
lgd={'unsorted', 'sorted', 'middle', 'numeric end', 'end', 'keep unsorted', 'keep sorted'};
T(1,:)=mean([t1, t2, t3, t4, t5, t6, t7]).'*1000;
clearvars -except to_* lgd T X NE
X=X.';
t1 = zeros(40,1);
t2 = t1;
t3 = t1;
t4 = t1;
t5 = t1;
t6 = t1;
t7 = t1;
for K = 1 : length(t1);
x1 = X;
t0 = tic;
x1(to_delete_unsorted) = [];
t1(K) = toc(t0);
x2 = X;
t0 = tic;
x2(to_delete_sorted) = [];
t2(K) = toc(t0);
x3 = X;
t0 = tic;
x3(500:500+NE-1) = [];
t3(K) = toc(t0);
x4 = X;
t0 = tic;
x4(10000-NE+1:10000) = [];
t4(K) = toc(t0);
x5 = X;
t0 = tic;
x5(10000-NE+1:end) = [];
t5(K) = toc(t0);
x6 = X;
t0 = tic;
x6 = x6(to_keep_unsorted);
t6(K) = toc(t0);
x7 = X;
t0 = tic;
x7 = x7(to_keep_sorted);
t7(K) = toc(t0);
end
t1 = t1(2:end); t2 = t2(2:end); t3 = t3(2:end); t4 = t4(2:end);
t5 = t5(2:end); t6 = t6(2:end); t7 = t7(2:end);
T(2,:)=mean([t1, t2, t3, t4, t5, t6, t7]).'*1000;
x=categorical(lgd,lgd,'ordinal',1);
bar(x,T.','grouped')
legend('Row Vector','Column Vector','location','northeast')
OK, one last perturbation...what if use logical addressing instead of explicit?
That's the ticket! The times are now all on the same scale and down by an order of magnitude for the deletion operations with the variable subscript expression in lieu of constant. Seems to confirm earlier conjecture on the boilerplate dynamic validation breaking things since verification for a logical array only would require that the size of the logical be commensurate with the array since anything nonzero is interpreted as true.
format long g
X = rand(1,10000);
NE = 9000;
to_delete_logical=false(size(X));
to_delete_unsorted = randperm(numel(X), NE);
to_delete_sorted = sort(to_delete_unsorted);
to_delete_logical_unsorted = to_delete_logical(to_delete_unsorted)==true;
to_delete_logical_sorted = to_delete_logical(to_delete_sorted)==true;
to_keep_sorted = setdiff(1:width(X), to_delete_sorted);
to_keep_unsorted = to_keep_sorted(randperm(length(to_keep_sorted)));
t1 = zeros(40,1);
t2 = t1;
t3 = t1;
t4 = t1;
t5 = t1;
t6 = t1;
t7 = t1;
for K = 1:length(t1);
x1 = X;
t0 = tic;
x1(to_delete_logical_unsorted) = [];
t1(K) = toc(t0);
x2 = X;
t0 = tic;
x2(to_delete_logical_sorted) = [];
t2(K) = toc(t0);
x3 = X;
t0 = tic;
x3(500:500+NE-1) = [];
t3(K) = toc(t0);
x4 = X;
t0 = tic;
x4(10000-NE+1:10000) = [];
t4(K) = toc(t0);
x5 = X;
t0 = tic;
x5(10000-NE+1:end) = [];
t5(K) = toc(t0);
x6 = X;
t0 = tic;
x6 = x6(to_keep_unsorted);
t6(K) = toc(t0);
x7 = X;
t0 = tic;
x7 = x7(to_keep_sorted);
t7(K) = toc(t0);
end
t1 = t1(2:end); t2 = t2(2:end); t3 = t3(2:end); t4 = t4(2:end);
t5 = t5(2:end); t6 = t6(2:end); t7 = t7(2:end);
lgd={'unsorted logical', 'sorted logical', 'middle', 'numeric end', 'end', 'keep unsorted', 'keep sorted'};
T(1,:)=mean([t1, t2, t3, t4, t5, t6, t7]).'*1000;
clearvars -except to_* lgd T X NE
X=X.';
t1 = zeros(40,1);
t2 = t1;
t3 = t1;
t4 = t1;
t5 = t1;
t6 = t1;
t7 = t1;
for K = 1 : length(t1);
x1 = X;
t0 = tic;
x1(to_delete_logical_unsorted) = [];
t1(K) = toc(t0);
x2 = X;
t0 = tic;
x2(to_delete_logical_sorted) = [];
t2(K) = toc(t0);
x3 = X;
t0 = tic;
x3(500:500+NE-1) = [];
t3(K) = toc(t0);
x4 = X;
t0 = tic;
x4(10000-NE+1:10000) = [];
t4(K) = toc(t0);
x5 = X;
t0 = tic;
x5(10000-NE+1:end) = [];
t5(K) = toc(t0);
x6 = X;
t0 = tic;
x6 = x6(to_keep_unsorted);
t6(K) = toc(t0);
x7 = X;
t0 = tic;
x7 = x7(to_keep_sorted);
t7(K) = toc(t0);
end
t1 = t1(2:end); t2 = t2(2:end); t3 = t3(2:end); t4 = t4(2:end);
t5 = t5(2:end); t6 = t6(2:end); t7 = t7(2:end);
T(2,:)=mean([t1, t2, t3, t4, t5, t6, t7]).'*1000;
x=categorical(lgd,lgd,'ordinal',1);
bar(x,T.','grouped')
legend('Row Vector','Column Vector','location','northeast')

Sign in to comment.

More Answers (1)

I remember past tests showing that extraction was more efficient, but that was many years and Matlab versions ago. It still appears to be true, at least in some circumstances. At minimum, this means deletion is not provably better.
N=3e7;
x=rand(N,1);
timeit(@() x(1:N-1),1)
ans = 0.1256
timeit(@() parenDel(x,N),1)
ans = 0.2375
function x=parenDel(x,N)
x(N)=[];
end
function x=parenRef(x,N)
x=x(1:N-1);
end

4 Comments

How much of the difference might be owing to the use of a function in the deletion test as against direct inline instruction for the extraction?
Fair point. But I've now revised the test so that neither version is inline. The difference is the same.
I suspect that a deletion statement,
x(I)=[];
is implemented internally as,
x = x(setdiff(1:N,I));
The extra overhead of the setdiff operation might be the reason for the slower performance.
N=3e7;
x=rand(N,1);
timeit(@() parenRef(x,N),1)
ans = 0.1321
timeit(@() parenDel(x,N),1)
ans = 0.2373
function x=parenDel(x,N)
x(N)=[];
end
function x=parenRef(x,N)
x=x(1:N-1);
end
Just added the explicit function ref for the extraction; seems to be about 10% slower than the prior inline, maybe. However, this and @Walter Roberson's results below seem in direct contradiction unless I'm misreading them?
On reflection I had come to the conclusion that from a purely straightforward process that the extraction case should generally outperform the deletion method owing to the parsing or RHS vs LHS would create a new memory object as a result of the selection in the former that can then just be assigned to the LHS whereas the [] on the RHS will imply a "move in place" that has to do physical reallocation which has similar issues of copy as is noted in the documentation in the case of preallocation.
I'm confused at this point as to how the two test results come out as they do...

Sign in to comment.

Products

Release

R2026b

Asked:

on 5 Oct 2026 at 12:09

Edited:

dpb
on 10 Oct 2026 at 13:52

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!