arrays - Split vector in MATLAB -
i'm trying elegantly split vector. example,
vec = [1 2 3 4 5 6 7 8 9 10] according vector of 0's , 1's of same length 1's indicate vector should split - or rather cut:
cut = [0 0 0 1 0 0 0 0 1 0] giving cell output similar following:
[1 2 3] [5 6 7 8] [10]
solution code
you can use cumsum & accumarray efficient solution -
%// create id/labels use accumarray later on id = cumsum(cut)+1 %// mask valid values cut , vec corresponding ones in cut mask = cut==0 %// output accumarray using masked ids , vec values out = accumarray(id(mask).',vec(mask).',[],@(x) {x}) benchmarking
here performance numbers when using large input on 3 popular approaches listed solve problem -
n = 100000; %// input datasize vec = randi(100,1,n); %// random inputs cut = randi(2,1,n)-1; disp('-------------------- cumsum + accumarray') tic id = cumsum(cut)+1; mask = cut==0; out = accumarray(id(mask).',vec(mask).',[],@(x) {x}); toc disp('-------------------- find + arrayfun') tic n = numel(vec); ind = find(cut); ind_before = [ind-1 n]; ind_before(ind_before < 1) = 1; ind_after = [1 ind+1]; ind_after(ind_after > n) = n; out = arrayfun(@(x,y) vec(x:y), ind_after, ind_before, 'uni', 0); toc disp('-------------------- cumsum + arrayfun') tic cutsum = cumsum(cut); cutsum(cut == 1) = nan; %don't include cut indices sumvals = unique(cutsum); % find values use in indexing vec output sumvals(isnan(sumvals)) = []; %remove nan values sumvals output = arrayfun(@(val) vec(cutsum == val), sumvals, 'uniformoutput', 0); toc runtimes
-------------------- cumsum + accumarray elapsed time 0.068102 seconds. -------------------- find + arrayfun elapsed time 0.117953 seconds. -------------------- cumsum + arrayfun elapsed time 12.560973 seconds. special case scenario: in cases might have runs of 1's, need modify few things listed next -
%// mask valid values cut , vec corresponding ones in cut mask = cut==0 %// setup ids differently time. idea have successive ids. id = cumsum(cut)+1 [~,~,id] = unique(id(mask)) %// output accumarray using masked ids , vec values out = accumarray(id(:),vec(mask).',[],@(x) {x}) sample run such case -
>> vec vec = 1 2 3 4 5 6 7 8 9 10 >> cut cut = 1 0 0 1 1 0 0 0 1 0 >> celldisp(out) out{1} = 2 3 out{2} = 6 7 8 out{3} = 10
Comments
Post a Comment