2016-04-05 5 views
3

私は配列(1と0など)を持っていて、1がn回​​連続して表示される最初の場所のインデックスiを探したいと思います。例えば条件が真でn回連続していることを確認する

x = [0 0 1 0 1 1 1 0 0 0] ; 

I = 5、N = 3用、これが初めてであるように '1' の行で3回現れます。

注:私はこれが私の最初のn 1sの指標を与えるように行の1が表示されますn回

i = find(x,n,'first'); 

が間違っているところを見つけるしたいと思います。

これは本質的に文字列検索ですか?例えばfindstrだがベクトルを使う。

+0

あなたはループでOKですか? –

+0

@MadPhysicistループするのはうれしいです。 – tannoreth

+5

あなたはループしていませんか? –

答えて

6

次のようにして、コンボリューションでそれを行うことができます:それはN 1のベクトルでコンボルブx

を動作し、結果はNに等しい最初の時間を見つける方法

x = [0 0 1 0 1 1 1 0 0 0]; 
N = 3; 
result = find(conv(x, ones(1,N), 'valid')==N, 1) 

を。畳み込みは'valid'フラグで計算され、エッジ効果を回避し、インデックスの正しい値を取得します。

+0

@rayryengありがとう!私はこの1つと正規表現の間で引き裂かれました:-) –

+0

'i = find(conv(x、ones(1、N)、 'valid')== N、1、 'last')'最後の時刻を見つけますn 1sが表示されますか? – tannoreth

+2

@タンノレスはい。 – Adriaan

4

バッファ行列を生成することです。ここで、この行列の各行は、配列の重複したn要素です。これを作成したら、配列にインデックスを付けて、1をすべて含む最初の行を見つけます:

x = [0 0 1 0 1 1 1 0 0 0]; %// Example data 
n = 3; %// How many times we look for duplication 

%// Solution 
ind = bsxfun(@plus, (1:numel(x)-n+1).', 0:n-1); %' 
out = find(all(x(ind),2), 1); 

最初の行は微妙です。 bsxfunを使用してサイズm x nの行列を生成します。ここで、mはオーバーラップする近傍の総数です。nは検索するウィンドウのサイズです。これは、1行目が1からnまで列挙され、2行目が2からn+1まで列挙され、最後までnumel(x)-n+1からnumel(x)までの行列が生成されます。 n = 3を考えると、私たちは持っている:

>> ind 

ind = 

    1  2  3 
    2  3  4 
    3  4  5 
    4  5  6 
    5  6  7 
    6  7  8 
    7  8  9 
    8  9 10 

これらの私たちは、配列xへのインデックスとして使用するインデックスがあり、そしてあなたの例のためには、次のバッファ行列を生成する際にxに、私たちは直接インデックス:

>> x = [0 0 1 0 1 1 1 0 0 0]; 
>> x(ind) 

ans = 

    0  0  1 
    0  1  0 
    1  0  1 
    0  1  1 
    1  1  1 
    1  1  0 
    1  0  0 
    0  0  0 

各行は、n要素の重複する近傍です。私たちは最終的に私たちにすべて1を与える最初の行を検索することで終わります。これは、allを使用し、2を2番目のパラメータとして、すべての行を独立して検索することによって行われます。 allは、行のすべての要素がゼロでない場合はtrueを生成します。次に、findと組み合わせて、この制約を満たす最初の非ゼロ位置を決定します。そのため:

>> out = find(all(x(ind), 2), 1) 

out = 

    5 

これは、この重複の始まりはn回発生場所xの第五の場所があることを教えてくれる。ループと

1

一つの可能​​性は:

i = 0; 
n = 3; 

for idx = n : length(x) 
    idx_true = 1; 
    for sub_idx = (idx - n + 1) : idx 
     idx_true = idx_true & (x(sub_idx)); 
    end 
    if(idx_true) 
     i = idx - n + 1; 
     break 
    end 
end 

if (i == 0) 
    disp('No index found.') 
else 
    disp(i) 
end 
+0

良い標準的なアプローチ。おそらく、伝統的なコンパイル言語の標準的な答えだろう。 +1。 – rayryeng

2

Rayryeng's approachあなたはこのようにもループすることができますに基づいています。これは間違いなく短い配列サイズの方が遅くなりますが、非常に大きな配列サイズの場合、これはすべての可能性を計算するのではなく、最初の一致が見つかると直ちに停止し、より高速になります。最初の配列の長さに基づいてifステートメントを使用して、bsxfunを使用するか、forループを使用するかを選択することもできます。最新のMATLABエンジンアップデート以降、forループはかなり高速です。

x = [0 0 1 0 1 1 1 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 1 0 1 1 1 0 0 0]; %// Example data 
n = 3; %// How many times we look for duplication 
a = 2; %// number of desired matches 
collect(1,a)=0; %// initialise output 
kk = 1; %// initialise counter 

for idx = 1:numel(x)-n 
    if all(x(idx:idx+n-1)) 
     collect(kk) = idx; 
     if kk == a 
      break 
     end 
     kk = kk+1; 
    end 
end 

同じことを行いますがaマッチが発見された後にシャットダウンします:

x = [0 0 1 0 1 1 1 0 0 0]; %// Example data 
n = 3; %// How many times we look for duplication 

for idx = 1:numel(x)-n 
    if all(x(idx:idx+n-1)) 
     break 
    end 
end 

はまた、これはa最初の出現を検索するために使用することができます。繰り返しますが、この方法は、配列が大きい場合にのみ便利です。

commentedあなたが最後に見つかったかどうかを確認する:はい。前と同じトリック、ちょうど後ろにループを実行:

for idx = numel(x)-n:-1:1 
    if all(x(idx:idx+n-1)) 
     break 
    end 
end 
+1

これは良いことです。実際には、 'all(x(idx:idx + n-1))'を 'sum(x(idx:idx + n-1))== n 'に置き換えると、これは本質的にLuis提案された。私は初期の休憩が好きです。 – rayryeng

関連する問題