I have about 100,000 numbers that I would like to group together based on dividing by two or increments of two.
PS: The increment values may change and the values found in the main array "x" can only be used once.
I'm not sure how to check and stop the loop if a number in the "array_all" array has been repeated from the "x" array.
See example below
Example:
x=[9,8,7,6,5,4,3,2,1]
I'm trying to get the array_all array to look like this:
array_all=
[ 9.00000 4.50000 2.25000
8.00000 4.00000 2.00000
7.00000 3.50000 1.75000
6.00000 3.00000 1.50000
5.00000 2.50000 1.25000
1.00000 0.50000 0.25000]
and the dynamically named arrays to look like this
array_dyn_name1=[9,4.5,2.25]
array_dyn_name2=[8,4,2]
array_dyn_name3=[7,3.5,1.75]
array_dyn_name4=[6,3,1.5]
array_dyn_name5=[5,2.5,1.25]
array_dyn_name6=[1,.5,.25]
PS: The reason I don't just stop at the array "array_dyn_name6" is due to that the numbers will not be that simple there will be thousands. And I won't know when they will repeat.
Sequence of events:
1. Start from the highest number in the x array and divide that number and it's output number by two and place that into another array called array_all, do this 3 times
2. Place each row of array_all into a dynamically named array called array_dyn_name
3. Do this for each value in the x array unless the number has already been used before in the array_all array
Note: As you can see the array_all array don't start with 4,3, or 2 because they were previously used in the array_all array
The code below works but I'm not sure how to check and stop the loop if a number in the "array_all" array has been repeated from the "x" array.
%test grouping
clear all, clc, tic, clf;
x=[9,8,7,6,5,4,3,2,1]
div=[1,2,4] %numbers to use as divisor
array_all=[];
for ii=1:length(x)
for jj=1:length(div)
array_all(ii,jj)=x(ii)/div(jj) %divide each number and successive number by div
end
genvarname('array_dyn_name', num2str(ii)) %create dynamic variable
eval(['array_dyn_name' num2str(ii) '= array_all(ii,:)']) %places row into dynamic variable
end
fprintf('\nfinally Done-elapsed time -%4.4fsec- or -%4.4fmins- or -%4.4fhours-\n',toc,toc/60,toc/3600);
My output is below:
array_all =
9.00000 4.50000 2.25000
8.00000 4.00000 2.00000
7.00000 3.50000 1.75000
6.00000 3.00000 1.50000
5.00000 2.50000 1.25000
4.00000 2.00000 1.00000
3.00000 1.50000 0.75000
2.00000 1.00000 0.50000
1.00000 0.50000 0.25000
PS: I'm using octave 3.8.1 it's like matlab
You can try
array_all = bsxfun( @times, x(:), [1 .5 .25] ); %// generate for all values
Now, using ismember we prune the rows of array_all
[Lia Locb] = ismember( x(:), reshape( array_all.', [], 1 ) ); %// order elements of array_all row by row
By construction all elements of x are in array_all but we want to prune rows for which the first element already appears in previous rows.
firstRowToAppearIn = ceil(Locb/3);
So
toBePruned = 1:numel(x) > firstRowToAppearIn; %// prune elements that appear in array_all in a row preceding their location in x
array_all(toBePruned,:) = []; %// remove those lines
Now we can define array_dyn_name-s according to array_all.
Using eval is HORRIBLE, instead we use structure with dynamic field names:
st = struct();
for ii=1:size(array_all,1)
nm = sprintf('array_dyn_name%d',ii);
st.(nm) = array_all(ii,:);
end
It seems like ismember's second output (Locb) might be ordered differently between Matlab and octave (and maybe between newer and older versions of matlab). So, here's an alternative, using bsxfun:
eq_ = bsxfun( @eq, array_all, permute( x(:), [3 2 1] ) );
eq_ = max( eq_, [], 2 ); %// we do not care at which column of array_all x appeared
[mx firstRowToAppearIn] = max( squeeze(eq_), [], 1 );
PS,
Apart from using eval, there is another cavity in your implementation: you do not pre-allocate space for array_all - this may cause your code to run significantly slower than it actually needs to be. See, for example this thread about pre-allocation.
来源:https://stackoverflow.com/questions/28263795/numerical-grouping-using-matlab-octave-and-not-repeating-values-found-in-main