1

I have an array with n dimensions, and I have a sequence along one dimension at a certain location on all other dimensions. How do I find the location of this sequence? Preferably without loops.

I use matlab. I know what dimension it should be in, but the sequence isnt necessarily there. Find and == dont work. I could make an nd find function using crosscorrelation but Im guessing this is already implemented and I just dont know what function to call.

example:

ND = rand(10,10,10,10);
V = ND(randi(10),randi(10),randi(10),:);
[I1, I2, I3] = find(ND==V);

Edit: The sequence to be found spans the entire dimension it is on, I did not mention this in my original formulation of the problem. Knedlsepp`s solution solves exactly the problem I had, but Luis' solution solves a more general problem for when the sequence doesn't necessarily span the entire dimension.

6
  • 1
    Have you tried with correlation? I guess you can correlate the sequence with the matrix and the point with highest corr (if it is exactly equal corr=1) will be the one you want. This way you will be able to see if the sequence is repeated in different places also. Commented Jan 19, 2015 at 15:10
  • 2
    Do you already know which dimension you are looking along (eg in the example you gave, do you know to look along the third dimension?) Commented Jan 19, 2015 at 15:11
  • Yes I do know the dimension Commented Jan 19, 2015 at 15:25
  • 2
    Bit off-topic, but instead of round(10*rand) you should use randi(10). As the first one will yield integers from 0 to 10. Commented Jan 19, 2015 at 15:26
  • Is it possible that the pattern doesn't appear once? For example: ND = [1 2 1 2; 3 4 5 6], V = [1 2], search along 2nd dim Commented Jan 19, 2015 at 15:39

3 Answers 3

4

As there are multiple ways to interpret your question, I will clarify: This approach assumes a 1D sequence of size: numel(V) == size(ND, dimToSearch). So, for V = [1,2] and ND = [1,2,1,2] it is not applicable. If you want this functionality go with Luis Mendo's answer, if not this will likely be faster.

This will be a perfect opportunity to use bsxfun:

We start with some example data:

ND = rand(10,10,10,10);
V = ND(3,2,:,3);

If you don't have the vector V given in the correct dimension (in this case [1,1,10,1]) you can reshape it in the following way:

dimToSearch = 3;
Vdims = ones(1, ndims(ND)); 
Vdims(dimToSearch) = numel(V);
V = reshape(V, Vdims);

Now we generate a cell that will hold the indices of the matches:

I = cell(1, ndims(ND));

At this point we compute the size of ND if it were collapsed along the dimension dimToSearch (we compute dimToSearch according to V, as at this point it will have the correct dimensions):

dimToSearch = find(size(V)>1);
collapsedDims = size(ND); 
collapsedDims(dimToSearch) = 1;

Finally the part where we actually look for the pattern:

[I{:}] = ind2sub(collapsedDims, find(all(bsxfun(@eq, ND, V), dimToSearch)));

This is done in the following way: bsxfun(@eq, ND, V) will implicitly repmat the array V so it has the same dimensions as ND and do an equality comparison. After this we do a check with all to see if all the entries in the dimension dimToSearch are equal. The calls to find and ind2sub will then generate the correct indices to your data.

Sign up to request clarification or add additional context in comments.

9 Comments

dim could be replaced with find(size(V)>1) for a generic one?
Generally my arrays have n>3
Does this really work? I'm trying with ND = [1 2 1 4; 3 1 2 6], V = [1 2] and getting an error (maybe I understood the question wrongly)
@Leo: You will have to use ind2sub there. Give me a sec.
@LuisMendo: Let me read the question again. I was given the impression that V would be given in the correct way (V = [1;2])
|
2

Let d be the dimension along which to search. I'm assuming that the sought sequence V may be shorter than size(ND,d). So the sequence may appear once, more than once, or never along each dimension-d- "thread".

The following code uses num2cell to reshape ND into a cell array such that each dimension-d-thread is in a different cell. Then strfind is applied to each cell to determine matches with V, and the result is a cell array with the same dimensions as ND, but where the dimension d is a singleton. The contents of each cell tell the d-dimension-positions of the matches, if any.

Credit goes to @knedlsepp for his suggestion to use num2cell, which greatly simplified the code.

ND = cat(3, [1 2 1 2; 3 4 5 6],[2 1 0 5; 0 0 1 2] ); %// example. 2x4x2
V = 1:2; %// sought pattern. It doesn't matter if it's a row, or a column, or...
d = 2; %// dimension along which to search for pattern V
result = cellfun(@(x) strfind(x(:).', V(:).'), num2cell(ND,d), 'UniformOutput', 0);

This gives

ND(:,:,1) =
     1     2     1     2
     3     4     5     6
ND(:,:,2) =
     2     1     0     5
     0     0     1     2

V =
     1     2

result{1,1,1} =
     1     3    %// V appears twice (at cols 1 and 3) in 1st row, 1st slice
result{2,1,1} =
     []         %// V doesn't appear in 2nd row, 1st slice
result{1,1,2} =
     []         %// V appears appear in 1st row, 2nd slice
result{2,1,2} =
     3          %// V appears once (at col 3) in 2nd row, 2nd slice

8 Comments

Oh! I just now understood what you meant by your comment to my answer! I thought the OP was given a pattern of size numel(V) == size(ND, d)!
@knedlsepp And now I see what your answer was doing, and why it could be done so simply :-) Well, we'll see what the OP really wanted. The question was not very clear indeed
After stepping through your solution to understand what's going on, I think you might be able to simplify by using result = cellfun(@(x) strfind(x(:).', V(:).'), num2cell(ND,d), 'uni', 0)
@knedlsepp Good one! I always forget about num2cell. It simplifies things a lot in this case. I think you should make it a separate answer! Or add it to your answer, that is
@Leo Yes, in that case knedlsepp's answer does what you want. I've edited my answer to reflect my interpretation of the question.
|
0

One not very optimal way of doing it:

    dims = size(ND);
    Vrep = repmat(V, [dims(1), dims(2), dims(3), 1]);
    ND_V_dist = sqrt(sum(abs(ND.^2-Vrep.^2), 4));
    iI = find(ND_V_dist==0);
    [I1, I2, I3] = ind2sub([dims(1), dims(2), dims(3)], iI);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.