How can I check if a specific set of numbers are present in my array?

45 ビュー (過去 30 日間)
Luqman Saleem
Luqman Saleem 2019 年 2 月 28 日
コメント済み: Adam Danz 2019 年 2 月 28 日
Let I have a 1D array A of real positive increasing integers of length N. I want to check if the elements in it have natural order (and not missing any natural number). let me explain it with exampls:
Example 1:
A = [ 2 5 7 8 9 14 16]
there are 3 ordered numbers from 7 to 9, [7 8 9]. I want to write a code which can show me these numbers.
Example 2:
B = [ 1 4 5 6 7 8 10 11 12 16 20 ]
in this array there are two ordered set of numbers, one [4 5 6 7 8] and other is [10 11 12]. I want my code to display both of them. hmm... I want to have power to decide the minimum length of ordered numbers.
Example 3 (final):
C = [ 1 2 3 4 5 11 14 15 16 17 18 22 25 26 30 31 32]
Let I say that minimum length to choose ordered number is 3 then, there are three such pairs in C, [1 2 3 4 5], [14 15 16 17 18] and [30 31 32].
Hope I have made my question clear.
  1 件のコメント
Jos (10584)
Jos (10584) 2019 年 2 月 28 日
What have you tried so far? I suggest you look into
  • diff
  • logical indexing
  • find

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

採用された回答

Adam Danz
Adam Danz 2019 年 2 月 28 日
編集済み: Adam Danz 2019 年 2 月 28 日
In this solution, the vector C is differentiated and then we find the starting point of each consecutive segment of 1s using bwlabel() (image processing toolbox). The rest is pretty much straight forward. I'm not sure what you're going to do with these consecutive segments but I've stored them in a cell array 'consecs' and put them into a table 'T' to show you how you pull them out of the vector C and display their start/end indices. Set the variable 'm' to the minimum length of consecutive numbers accepted.
C = [ 1 2 3 4 5 11 14 15 16 17 18 22 25 26 30 31 32];
m = 3; % minimum length of consecutive numbers
% Identify the start/end index of all consecutive numbers
dC = bwlabel(diff(C)==1); % requires image processing toolbox
startIdx = arrayfun(@(x) find(dC == x,1), unique(dC));
endIdx = arrayfun(@(x,y)sum(dC == x)+y, unique(dC), startIdx);
% Get rid of start/stop indices of length '0' (they are meaningless)
startIdx(unique(dC)==0) = [];
endIdx(unique(dC)==0) = [];
% get rid of any that are below the minimum length
len = endIdx - startIdx +1;
startIdx(len < m) = [];
endIdx(len < m) = [];
% Pull out the consecutive numbers have have a length equal to or greater than m
consecs = arrayfun(@(x,y) C(x):C(y), startIdx, endIdx, 'UniformOutput', false)';
% Show results in a table
T = table(startIdx', endIdx', consecs, 'VariableNames', {'StartIndex', 'StopIndex', 'Consecs'})
And the result
T =
3×3 table
StartIndex StopIndex Consecs
__________ _________ ____________
1 5 [1×5 double]
7 11 [1×5 double]
15 17 [1×3 double]
>> T.Consecs{1}
ans =
1 2 3 4 5
>> T.Consecs{2}
ans =
14 15 16 17 18
>> T.Consecs{3}
ans =
30 31 32
  3 件のコメント
Adam Danz
Adam Danz 2019 年 2 月 28 日
編集済み: Adam Danz 2019 年 2 月 28 日
Glad it worked out! Note that if you change the variable name "C" you'll have to make that change to a few of lines in that code that reference 'C' - particularly the arrayfuns.
Jos (10584)
Jos (10584) 2019 年 2 月 28 日
Nice approach, but a lot of code for a simple problem :-)

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

その他の回答 (2 件)

Jos (10584)
Jos (10584) 2019 年 2 月 28 日
編集済み: Jos (10584) 2019 年 2 月 28 日
I cannot resist to put the "simple" matlab version here. Note that this problem is closely related to Run-Length Encoding schemes.
% the data
C = [ 1 2 3 4 5 11 14 15 16 17 18 22 25 26 30 31 32]
MinLength = 3 ;
% the engine
dC = diff([false diff(C)==1 false]) % true for consecutive numbers in C ("natural order")
% now finding the sequences of trues in dC is easy
S1 = find(dC == 1) % start indices of these sequences
S2 = find(dC == -1) % end indices
r = find(S2-S1+1 >= MinLength) ; % select those sequences with minimum lengths
OUT = arrayfun(@(k) C(S1(k):S2(k)), r, 'un', 0) % get those sequences
  1 件のコメント
Adam Danz
Adam Danz 2019 年 2 月 28 日
+1 The double differentiation method is faster and cleaner.

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


Sven
Sven 2019 年 2 月 28 日
This example is even fast for large arrays and looks easier to understand. So depending on how large the array you are searching is this might be more appropriate.
function sets = getUniqueSetsOfOrderedNumbers(arr, minLength)
sets = {};
k = 0;
setLength = 1;
for i = 2:length(arr)
% Check the difference between neighbouring numbers
if arr(i) - arr(i-1) == 1
setLength = setLength + 1;
else % the natural number order broke
if setLength >= minLength % Yes? -> we found a long enough set
k = k + 1;
sets{k} = arr(i-setLength:i-1);
end
setLength = 1;
end
end
% Check again in case arr ended with ordered numbers
% In this case it didn't enter the else block to check num again
if setLength >= minLength
k = k + 1;
sets{k} = arr(i-setLength+1:i);
end
end

カテゴリ

Help Center および File ExchangeLogical についてさらに検索

Community Treasure Hunt

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

Start Hunting!

Translated by