I am trying to eliminate a loop from an operation. If it can't be done, I'm trying to understand why using a loop to create a string command for eval is so much faster than doing the more conventional calculation.

I have a large matrix, X , of size k by m filled with i.i.d. random integers from 1 to n (for some variable n<k). I want to collect the indices of all columns that contain each integer from 1 to n at least once. I essentially want to execute:
my_indices = any(X==1) & any(X==2) & ... & any(X==n);
Obviously, without knowing n I cannot take this approach and even for fixed but large n, I might not want to write such a long line of code. I'm curious if there is a clever way to do this without any loop.
Also, if it requires a loop, is it better to use a loop to create a string for the command, or is it better to use a loop to just execute each one of the any operations and combine it with the previous results?
So, for example, both of the following approaches coded below give the same result. I was surprised to see that the first is an order of magnitude faster for some values of m although behavior is inconsistent (even though I've never had any good luck with eval before).
n = 6; %maximum possible random integer
k = 10; %number of rows of X
m = 1e6; %number of columns of X
X = ceil(n*rand(k,m));
%This approach creates a string for the command I want to execute and uses eval
str = [ ]; %empty string
for i=1:n %loop over
str = [ str 'any( X== ' num2str(i) ' ) & ']; %concatenate pieces
end
str = str(1:end-2); %remove the final &
my_indices = eval( str ); %execute the string
%This approach avoids using eval
my_indices2 = true(1,m);
for i=1:n
my_indices2 = my_indices2 & any(X==i);
end

Answers (2)

Assuming you want the indexes themselves:
n = whatever;
C = mat2cell(X,size(X,1),ones(1,size(X,2)));
my_indices = find(cellfun(@(x)numel(unique(x)),C) == n);
If you want a logical vector of size m that has the result, then don't do the "find" in the last line.
One possibility:
X = randi(20, 50);
Xm = max(X(:));
X_col = [];
for k1 = 1:size(X,2)
C = unique(X(:,k1)); % Unique Values In Column ‘k1’
if size(C,1) == Xm
X_col = [X_col k1]; % If ‘Xm’ Unique Values, Store ‘k1’
end
end
The ‘X_col’ vector has the column indices of the columns that have ‘Xm’ unique values, that is at least one of every random number in the sequence.

This question is closed.

Asked:

on 2 Jul 2015

Closed:

on 20 Aug 2021

Community Treasure Hunt

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

Start Hunting!