Find double repetitions in a (sorted) array.
古いコメントを表示
Given an array submitted in a form of struct field, containing integer numbers. For convenience, let's assume that the numbers are already sorted in ascending order:
>> s.x
ans =
2
ans =
2
ans =
5
ans =
5
ans =
5
ans =
8
ans =
8
Find indexes of elements, which occur exact 2 times:
ind =
1 2 6 7
4 件のコメント
Steven Lord
2017 年 10 月 20 日
Okay, done.
If you're having difficulty solving this problem, why don't you show us what you've tried and whatever warning, error, or unexpected result you received so we may be able to offer some suggestions.
The iterative growing of arrays is a standard mistake from the view point of efficiency. Simply pre-allocate:
d = diff(x);
j = 0;
ind = zeros(1, numel(d));
indi = 1;
for i=1:numel(d)
if d(i)==0
j=j+1;
else
if j==1
ind(indi) = i-1;
ind(indi+1) = i;
indi = indi + 2;
end
j=0;
end
end
ind = ind(1:indi-1);
This does not catch the case, if the last two elements are equal.
bbb_bbb
2017 年 10 月 21 日
採用された回答
その他の回答 (4 件)
It always pays off to get rid of loops and/or pre-allocating your output.
x= [2; 2; 5; 5; 5; 8; 8; 13; 13; 13; 13];
s = struct('x', num2cell(x));
x=[s.x];
%only newer releases: 0.000778 seconds
tic
count=histcounts(x,0.5 : max(x)+0.5);
ind=find(sum(x==find(count==2)'));
toc
%should work on most releases: 0.000628 seconds
tic
count=histcounts(x,0.5 : max(x)+0.5);
count=find(count==2);
ind=find(sum(repmat(x,length(count),1)==repmat(count',1,length(x))));
toc
%your loop: 0.001100 seconds
tic
d=diff(x); j=0; ind=[];
for i=1:numel(d)
if d(i)==0
j=j+1;
else
if j==1
ind(end+1)=i-1;
ind(end+1)=i;
end
j=0;
end
end
toc
8 件のコメント
bbb_bbb
2017 年 10 月 20 日
Ah yes, forgot to mention: the implicit expanding only works on newer releases (I think it works from 2015b or 2016a).
You do the expanding explicitly like this:
logical_array = repmat(x,length(a),1)==repmat(count',1,length(x));
ind=find(sum(logical_array));
bbb_bbb
2017 年 10 月 20 日
Rik
2017 年 10 月 20 日
a was the dummy variable name I used when I jotted down the code instead of count. I edited my previous comment accordingly.
And yes, ismember can be quite slow, but it's flexibility makes it suitable for many jobs. Although in this case, histcounts might be the culprit.
What you need to think about is that some function have an overhead to get started, but will scale much better. I would suggest testing it out on a real example and use the debugging tools to analyse the run time (the 'run and time' button).
Rik
2017 年 10 月 21 日
That's because x has a different shape:
x1= [2; 2; 5; 5; 5; 8; 8; 13; 13; 13; 13];
s = struct('x', num2cell(x1));
x2=[s.x];
x1 is 11x1 and x2 is 1x11
bbb_bbb
2017 年 10 月 21 日
Image Analyst
2017 年 10 月 20 日
You didn't tag it as homework. Is it? This will do it:
% Assignment of a struct with a field containing integer numbers
x= [2; 2; 5; 5; 5; 8; 8; 13; 13; 13; 13];
s = struct('x', num2cell(x));
numbers = [s.x]
[groupNumber, groupValue] = findgroups(numbers)
counts = histcounts(groupNumber)
ofGroupSize2 = find(counts == 2) % Find those only if they have a length of 2.
values = groupValue(ofGroupSize2)
indexes = find(ismember(numbers, values))
2 件のコメント
Image Analyst
2017 年 10 月 20 日
編集済み: Image Analyst
2017 年 10 月 21 日
You can use regionprops() instead of findgroups() if you have an old version and have the Image Processing Toolbox. See my separate answer with demo code.
Jan
2017 年 10 月 21 日
Your code looks like the input is sorted. The other approaches do not have this limitation. If it is really sorted:
d = [true; diff(x) ~= 0]; % TRUE if values change
b = x(d); % Elements without repetitions
k = find([d', true]); % Indices of changes
n = diff(k);
is2 = find(n==2);
ind4 = reshape([k(is2); k(is2)+1], 1, []);
Code taken from FEX: RunLength.
Image Analyst
2017 年 10 月 21 日
編集済み: Image Analyst
2017 年 10 月 21 日
If you have the Image Processing Toolbox, you can use regionprops():
% Assignment of a struct with a field containing integer numbers
x= [2; 2; 5; 5; 5; 8; 8; 13; 13; 13; 13];
s = struct('x', num2cell(x));
numbers = [s.x] % A labeled "image"
% Find lengths of each run of numbers plus the indexes where they occur.
props = regionprops(numbers, 'Area', 'PixelIdxList')
% Extract from structure into one vector.
allLengths = [props.Area]
% Find those only if they have a length of 2.
ofGroupSize2 = find(allLengths == 2)
% Find indexes of those runs with length 2.
indexes = [props(ofGroupSize2).PixelIdxList]
% Shape into row vector
indexes = reshape(sort(indexes(:)), 1, [])
カテゴリ
ヘルプ センター および File Exchange で Performance and Memory についてさらに検索
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!