Finding the first index of a row where all integers of a defined list have occurred

4 ビュー (過去 30 日間)
Steve 2023 年 1 月 27 日
コメント済み: Steve 2023 年 1 月 28 日
I have a 100x100 list values (1,2,3,4) selected at random.
x=randi([1,4],100,100);
Reading left to right, I want to find the first index in each row where all the numbers have appeared (1,2,3,4), irrespecitve of order or repeats.
For example, in the random data (4,2,3,2,4,4,1,1,2,4,2,3...), all numbers have appeared at index 7.
Does this require a loop?

サインインしてコメントする。

採用された回答

John D'Errico 2023 年 1 月 27 日
Given a vector, can you simply find the first index where all have occurred? Just use ismember.
x=randi([1,4],1,100)
x = 1×100
4 1 1 4 2 4 2 4 1 1 4 1 4 4 4 4 4 3 4 3 4 4 4 4 3 4 1 2 4 1
[~,locs] = ismember(1:4,x)
locs = 1×4
2 5 18 1
max(locs)
ans = 18
So max(locs) is the index at which point ALL of those elements have been seen. No loop was needed for that part. You could now just use a loop on the rows of a matrix with multiple rows.
Can you do this without a loop? Well, yes. The way to do it would require tools like mat2cell, and then cellfun. That is, you could convert the array to a cell array of vectors. Then use cellfun to apply the ismember operation (written as an m-file) to each vector.
Is it worth it, to write a code that you don't really understand, and will do what you want no more efficiently than a simple loop? A complicated looking line of code is not better than a simple loop. Remember, you need to understand that code in order to debug and maintain it in the future.
3 件のコメント表示非表示 2 件の古いコメント
Steve 2023 年 1 月 28 日
Thanks. I see, the max index of the first occurance is the last number to appear, and therefore all number have appeared at this point. Nice solution. Cheers!

サインインしてコメントする。

その他の回答 (1 件)

the cyclist 2023 年 1 月 27 日
I 100% agree with @John D'Errico's take on this, which is that any non-loop solution here is (probably) going to be sufficiently obfuscated that "future you" will regret avoiding the loops.
One reason is that there is no "natural" way to avoid loops is that find and ismember don't really have "row-wise" implementations (to my knowledge) that do what you are trying to do. (There is a bit of discussion of this in the forum.)
Here is an example of an obfuscated solution:
% The input
rng default
N = 4;
x=randi([1,N],100,100);
% The algorithm
% (Technically, I supposed this is a for loop, but not over your rows or columns)
loc = zeros(height(x),N);
for val = 1:N
[~,loc(:,val)] = max(x==val,[],2);
end
output = max(loc,[],2)
output = 100×1
5 5 5 5 12 15 12 8 6 5
Personally, I would use the loop, with John's solution.

サインインしてコメントする。

カテゴリ

Find more on Loops and Conditional Statements in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by