How to group numbers of a vector

조회 수: 6 (최근 30일)
BAM
BAM 2018년 9월 24일
댓글: BAM 2018년 11월 25일
Hi,
I have the following vector:
V = [1 2 3 5 7 9 11 13 14 15 16 17 20 22 24 26]
I would like to group the numbers according to their difference (step value) from each other so they look like:
Group 1 = [1 2 3]
Group 2 = [5 7 9 11 13]
Group 3 = [14 15 16 17]
Group 4 = [20 22 24 26]
Could anyone help me to sort out this?
Thank you!
  댓글 수: 6
Stephen23
Stephen23 2018년 9월 27일
편집: Stephen23 2018년 9월 27일
" Group 1 and 5 are incorrect as it is seen 339 should go in group 2 ..."
It is not enough to simply write that some groups "... are incorrect", because you have not told us anywhere what the algorithm is that you use to decide this. Image Analyst already asked you to clarify this. You stated that "...but the actual vectors that I work with consist only odd or even numbers, which makes the discrimination easier", but this does not explain 3 in your original example, and the number 339 in your comment above, both of which could fit into either group perfectly. You need to tell us exactly how to decide which group they fit into.
BAM
BAM 2018년 10월 1일
I was asked for a specific rule, so if the difference between the first and second value is <=2 and then between the second and third is <=2, these 3 values of the vector will be in the same group, but if the difference between third and fourth is >2 then the fourth value is discriminated from the first group. If the fourth and fifth values have a difference <=2 they will form the second group and so on.
I hope this time is clearer for you asking me for the rule. Thank you!!!

댓글을 달려면 로그인하십시오.

채택된 답변

Stephen23
Stephen23 2018년 9월 25일
편집: Stephen23 2018년 9월 25일
One solution based on diff and regexp:
>> V = [1 2 3 5 7 9 11 13 14 15 16 17 20 22 24 26];
>> X = [0,1,~diff(V,2)];
>> [B,E] = regexp(char('0'+X),'0+1*');
>> C = arrayfun(@(b,e){V(b:e)},B,E);
>> C{:}
ans =
1 2 3
ans =
5 7 9 11 13
ans =
14 15 16 17
ans =
20 22 24 26

추가 답변 (2개)

Bruno Luong
Bruno Luong 2018년 9월 26일
OK, try this:
b = [true, false, diff(V,2)~=0];
b = b & [true, ~b(1:end-1)];
b = find(b);
lgt = [b(2:end), length(V)+1] - b;
G = mat2cell(V,1,lgt);
G{:}
  댓글 수: 2
BAM
BAM 2018년 9월 26일
No change, still the same incorrect results.
BAM
BAM 2018년 9월 26일
Another vector with error:
V = [343 345 347 349 361 363 365 367 387 389 391 393 395 397 399 401 403 405 407 409 411 413 415 417 419 421 423 425 427 429 431 433 437 439 441 443 445 447 715 717 725 727 729 731 733 735 737 739 741 743 745 747 749 751 755 761 763 765 767 769 771 773 775 777]
In this vector 715 and 717 should go into another separate group and 755 as well.
Results:
G{1} = 343 345 347 349
G{2} = 361 363 365 367
G{3} = 387 389 391 393 395 397 399 401 403 405 407 409 411 413 415 417 419 421 423 425 427 429 431 433
G{4} = 437 439 441 443 445 447
G{5} = 715 717 725 727 729 731 733 735 737 739 741 743 745 747 749 751
G{6} = 755 761 763 765 767 769 771 773 775 777

댓글을 달려면 로그인하십시오.


Bruno Luong
Bruno Luong 2018년 9월 28일
편집: Bruno Luong 2018년 9월 28일
Can you try this one, I put the flag so that you can select if the common point that goes to left or right group, if you have other specific rule you need to specify it.
V = [315 339 341 343 345 347 349 351 ...
353 355 357 359 361 363 365 371 ...
373 375 377 379 381 387 389 391 ...
393 395 397 399 401 403 405 407 ...
409 411 413 415 417 419 421 423 ...
425 427 429 431 433 435 437 439 ...
441 443 445 447 449 473 727 729 ...
731 733 735 737 739 745 747]
GoLeftFlag = false; % choice of the common point goes to the left or right group
n = length(V);
d = diff([true, diff(V,2)==0, true]);
s = [1, find(d==1)];
e = [find(d==-1)+1, n];
collision = [0 e(1:end-1)]>=s;
if GoLeftFlag
s(collision) = s(collision) + 1;
else
collision(1) = [];
e(collision) = e(collision) - 1;
end
i2 = arrayfun(@(s,e) min(bsxfun(@plus,s:2:e,[0;1]),e), ...
e(1:end-1)+1, s(2:end)-1, 'unif', 0);
c = cell(1,2*size(s,2)-1);
c(1:2:end) = num2cell([s; e],1);
c(2:2:end-1) = i2;
i = cat(2,c{:});
lgt = diff(i,1,1)+1;
G = mat2cell(V,1,lgt);
G{:}
  댓글 수: 9
Bruno Luong
Bruno Luong 2018년 11월 23일
편집: Bruno Luong 2018년 11월 23일
OK I've modified the code to make group for only step <= 2. It looks ugly
V = [ 266 270 273 274 276 280 313 314 315 439 455 456 ...
457 471 472 473 474 475 476 863]
GoLeftFlag = false; % choice of the common point goes to the left or right group
n = length(V);
d = diff([true, diff(V,2)==0, true]); % & [true, c] & [c, true]);
s = [1, find(d==1)];
e = [find(d==-1)+1, n];
collision = [0 e(1:end-1)]>=s;
if GoLeftFlag
s(collision) = s(collision) + 1;
else
collision(1) = [];
e(collision) = e(collision) - 1;
end
i2 = arrayfun(@(s,e) min(bsxfun(@plus,s:2:e,[0;1]),e), ...
e(1:end-1)+1, s(2:end)-1, 'unif', 0);
c = cell(1,2*size(s,2)-1);
c(1:2:end) = num2cell([s; e],1);
c(2:2:end-1) = i2;
i = cat(2,c{:})';
% Make group only if step is <= 2
dv = diff(V(i),1,2)./diff(i,1,2);
stepbig = dv(:)>2;
s = [n,1];
up = accumarray(i(stepbig,1),1,s);
down = -accumarray(i(stepbig(1:end-1),2)+1,1,s);
g = accumarray(i(~stepbig,1),1,s);
lgt = diff(find([cumsum(up+down)+g; true]));
G = mat2cell(V,1,lgt);
G{:}
The result is
G{1} = 266
G{2} = 270
G{3} = 273 274
G{4} = 276
G{5} = 280
G{6} = 313 314 315
G{7} = 439
G{8} = 455 456 457
G{9} = 471 472 473 474 475
G{10} = 476
G{11} = 863
BAM
BAM 2018년 11월 25일
This is it!
You are a STAR Bruno!!! Your work is much appreciated. Thank you!
Just one last thing. I tried to find the minimum and maximum elements of these groups automatically, but I get errors, obviously I did wrong.
When I specify the group number it works, but then this is becoming a manual way of finding the min and max values.
For instance, I specified Group 9 and it works.
MIN = min(G{9})
MAX = max(G{9})
DIFF = MAX-MIN
MIN = 471
MAX = 475
DIFF = 4
Any ideas how the minimum and maximum elements of each group could be found automatically?

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Data Type Identification에 대해 자세히 알아보기

Community Treasure Hunt

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

Start Hunting!

Translated by