How can I select two out of 6 points for every page without loops?

I am trying to select two out of 6 points in an array whose size is 6x3xn. These two points are not in the same row on each page as I am trying to select those two of the six points that meet a certain condition. Let's assume that condition is that every coordinate is between 0 and 30.
Is there away to do this without loops?

8 Comments

Maybe I forgot to add that I know of logical indexing but I couldn't get my head around how they work in 3D especially in my case
"Let's assume that condition is that every coordinate is between 0 and 30. "
And does it garanty you get exactly 2 points out of 6?
No, there can also be the case that no points match the condition
So how you want to deal if the number of rows is not 2 and varies from page to page ?
It seems the problem is not well defined.
I would take Jan's solution and add this line after the creation of the mask:
mask = mask(:,:,sum(mask,1)==2);
So the number of pages that satisfies that (exactly 2 rows are find) would reduce. And you might keep track of which of those are not discarded, which are.
Your discription "... for every page" "...on each page" are missleading if not wrong.
I'm sorry, I only realized that I don't actually need the pages where not exactly two points are found after writing the question.

Sign in to comment.

 Accepted Answer

n = 2;
X = randi(40, 6, 3, n)
X =
X(:,:,1) = 25 18 19 19 23 18 26 5 7 15 39 10 22 35 10 26 35 23 X(:,:,2) = 35 22 6 25 29 2 5 39 5 34 33 36 32 14 17 5 22 33
mask = all(X >= 0 & X <= 30, 2)
mask = 6×1×2 logical array
mask(:,:,1) = 1 1 1 0 0 0 mask(:,:,2) = 0 1 0 0 0 0
Y = reshape(X(cat(2, mask, mask, mask)), [], 3)
Y = 4×3
25 23 7 19 5 25 26 19 29 18 18 2

6 Comments

Alternative to
cat(2, mask, mask, mask)
is
[mask mask mask]
or
repmat(mask, [1 3 1])
or
mask(:,[1 1 1],:)
or
mask(:,ones(1,3),:)
Only now I came to examine the code you provided more thoroughly and I realized that the coordinates selected by the mask are correct but unfortunately the points resulting from the reshape are not the same as in the array "X".
Is there a way to get the points from X in the same way they are saved there?
I think i found a way to do this:
mask = permute(mask,[2 1 3])
X = permute(X,[2 1 3])
This would be done before the reshaping
Nor Jan's code nor yours selects pages with exactly 2 (over 6) points that meet the filter constraints. The number of points to be selected per page is nowhere in the code.
The code selects ALL the points that meet the constraints, regardless where they are.
my code now looks like this
X = randi(40,6,3,4)
X =
X(:,:,1) = 12 17 1 32 6 13 35 9 16 2 24 17 20 35 34 10 16 30 X(:,:,2) = 10 3 40 5 30 35 27 22 40 3 35 11 33 29 21 31 7 7 X(:,:,3) = 4 25 17 25 25 8 2 34 4 32 12 25 36 20 7 19 25 32 X(:,:,4) = 10 26 3 33 15 27 19 4 34 2 31 27 30 19 25 12 19 8
mask = all(X>=0 & X<=30,2);
mask(:,:,sum(mask,1)~=2) = 0;
X = permute(X, [2 1 3]);
mask = permute(mask,[2 1 3])
mask = 1×6×4 logical array
mask(:,:,1) = 0 0 0 0 0 0 mask(:,:,2) = 0 0 0 0 0 0 mask(:,:,3) = 1 1 0 0 0 0 mask(:,:,4) = 0 0 0 0 0 0
X = reshape(X(cat(1,mask, mask, mask)),3,[])'
X = 2×3
4 25 17 25 25 8
So now 2 points only on pages where exactly 2 points meet the condition are selected
Sorry in case I have confused you
OK this looks correct. But I don't think you need permute and transpose at all. It seems like a side effect of your though trying to fix Jan's coden but that is not relevant.
n = 4;
nsolperpage = 2;
X = randi(40, [6, 3, n])
mask = all(X >= 0 & X <= 30, 2);
keep = sum(mask,1) == nsolperpage;
extractpages = find(keep)
mask(:,:,~keep) = false;
Y = reshape(X([mask, mask, mask]), nsolperpage, 3, [])

Sign in to comment.

More Answers (1)

n = 4;
nsolperpage = 2;
X = randi(40, [6, 3, n])
mask = all(X >= 0 & X <= 30, 2);
[~,p] = find(reshape(mask, [], n));
count = accumarray(p, 1, [n 1]);
keep = count == nsolperpage;
extractpages = find(keep)
mask(:,:,~keep) = false;
Y = reshape(X([mask, mask, mask]), nsolperpage, 3, [])

Products

Release

R2019b

Asked:

lit
on 10 Aug 2023

Edited:

on 15 Aug 2023

Community Treasure Hunt

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

Start Hunting!