Идентифицирайте пропуски в повтарящи се последователности

Имам вектор, който трябва да съдържа n последователности от 00 до 11

A = [00;01;02;03;04;05;06;07;08;09;10;11;00;01;02;03;04;05;06;07;08;09;10;11]

и бих искал да проверя дали последователността "00 - 11 " винаги се спазва (няма липсващи стойности).

например ако

A =[00;01;02;  04;05;06;07;08;09;10;11;00;01;02;03;04;05;06;07;08;09;10;11] 

(липсва 03 на 3-та позиция) За всяка липсваща стойност бих искал да върна тази информация в друг вектор

missing=
 [value_1,position_1;
 value_2, position_2;
 etc, etc]

Можеш ли да ми помогнеш?


person gabboshow    schedule 31.10.2013    source източник
comment
for цикъл и проверка дали разликата между две последователни стойности е 1... но предполагам, че има по-добри методи...   -  person gabboshow    schedule 31.10.2013
comment
Възможно ли е да липсват две съседни стойности? Например 00;01;02; 05;06.   -  person Luis Mendo    schedule 31.10.2013
comment
да, възможно е...   -  person gabboshow    schedule 31.10.2013
comment
Трудно е да направите това без цикъл, но arrayfun може да се справи с това в няколко реда. Решението обаче е доста непрозрачно (вижте моя отговор).   -  person chappjc    schedule 01.11.2013


Отговори (3)


Със сигурност знаем, че последният елемент трябва да е 11, така че вече можем да проверим за това и да улесним живота си за тестване на всички предишни елементи. Ние гарантираме, че A е 11-терминиран, така че подходът на „елементна промяна“ (по-долу) ще бъде валиден. Обърнете внимание, че същото важи и за началото, но промяната на A там ще затрудни индексите, така че е по-добре да се погрижим за това по-късно.

missing = [];
if A(end) ~= 11
    missing = [missing; 11, length(A) + 1];
    A = [A, 11];
end

След това можем да изчислим промяната dA = A(2:end) - A(1:end-1); от един елемент към друг и да идентифицираме позициите на пропуските idx_gap = find((dA~=1) & (dA~=-11));. Сега трябва да разширим всички липсващи индекси и очаквани стойности, като използваме ev за очакваната стойност. ev може да се получи от предишната стойност, както в

for k = 1 : length(idx_gap)
    ev = A(idx_gap(k));

Сега броят на елементите за попълване е промяната dA в тази позиция минус едно (защото едно означава липса на празнина). Обърнете внимание, че това може да се обвие, ако има празнина на границата между сегментите, така че използваме модула.

    for n = 1 : mod(dA(idx_gap(k)) - 1, 12)
        ev = mod(ev + 1, 12);
        missing = [missing; ev, idx_gap(k) + 1];
    end
end

Като тест разгледайте A = [5 6 7 8 9 10 3 4 5 6 7 8 9 10 11 0 1 2 3 4 6 7 8]. Това е случай, в който специалната инициализация от самото начало ще се задейства, запаметявайки вече липсващите 11 и променяйки A на [5 6 ... 7 8 11]. missing тогава ще отстъпи

11    24    % recognizes improper termination of A.
11     7
 0     7    % properly handles wrap-over here.
 1     7
 2     7
 5    21    % recognizes single element as missing.
 9    24
10    24

което трябва да е това, което очаквате. Това, което все още липсва, е началото на A, така че нека кажем missing = [0 : A(1) - 1, 1; missing];, за да завършим списъка.

person s.bandara    schedule 31.10.2013
comment
Да, този начин на индексиране е по-подходящ. Промених и това в инициализатора за missing. Обърнете внимание и на допълнителните записи в случай, че A не започва с 0, за които се грижи накрая. - person s.bandara; 31.10.2013

Това ще ви даде липсващите стойности и техните позиции в пълната последователност:

N = 11; % specify the repeating 0:N sub-sequence
n = 3; % reps of sub-sequence
A = [5 6 7 8 9 10 3 4 5 6 7 8 9 10 11 0 1 2 3 4 6 7 8]'; %' column from s.bandara

da = diff([A; N+1]); % EDITED to include missing end
skipLocs = find(~(da==1 | da==-N));
skipLength = da(skipLocs)-1;
skipLength(skipLength<0) = N + skipLength(skipLength<0) + 1;
firstSkipVal = A(skipLocs)+1;

patchFun = @(x,y)(0:y)'+x - (N+1)*(((0:y)'+x)>N);
patches = arrayfun(patchFun,firstSkipVal,skipLength-1,'uni',false);
locs = arrayfun(@(x,y)(x:x+y)',skipLocs+cumsum([A(1); skipLength(1:end-1)])+1,...
    skipLength-1,'uni',false);

След това ги съберете заедно, включително всички липсващи стойности в началото:

>> gapMap = [vertcat(patches{:}) vertcat(locs{:})-1]; % not including lead
>> gapMap = [repmat((0 : A(1) - 1)',1,2); gapMap] %' including lead
gapMap =
     0     0
     1     1
     2     2
     3     3
     4     4
    11    11
     0    12
     1    13
     2    14
     5    29
     9    33
    10    34
    11    35

Първата колона съдържа липсващите стойности. Втората колона е базираното на 0 местоположение в хипотетичната пълна последователност.

>> Afull = repmat(0:N,1,n)
>> isequal(gapMap(:,1), Afull(gapMap(:,2)+1)')
ans =
     1
person chappjc    schedule 31.10.2013

Въпреки че това не решава проблема ви напълно, можете да идентифицирате позицията на липсващите стойности или на групи от съседни липсващи стойности, като това:

ind = 1+find(~ismember(diff(A),[1 -11]));

ind дава позицията спрямо текущата последователност A, а не спрямо завършената последователност.

Например, с

A =[00;01;02;  04;05;06;07;08;09;10;11;00;01;02;03;    ;06;07;08;09;10;11]; 

това дава

>> ind = 1+find(~ismember(diff(A),[1 -11]))

ind =

     4
    16
person Luis Mendo    schedule 31.10.2013
comment
благодаря за отговора, но този код не ми предоставя информацията, от която се нуждая... в този случай бих искал да имам ind = [3 4; 4 16], което означава, че в позиция 4 липсва стойност 3, а в позиция 16 липсва стойност 4... - person gabboshow; 31.10.2013
comment
Знам. Беше замислено само като предложение. Може би можете да работите от това и да го завършите, за да отговаря на вашите нужди - person Luis Mendo; 31.10.2013