2016-06-19 8 views
3

文字列の複数のセル配列(> = 2)で共通要素を探したいと思います。文字列セルの共通要素を見つける方法は?

関連する質問はhereであり、答えはintersect()という機能を使用することを提案していますが、2つの入力に対してのみ機能します。

私の場合、2つ以上のセルがあり、共通のサブセットを1つだけ取得したいと考えています。ここで私が達成したいものの例です:のみこれらの2つの文字列がすべての入力で発生するので、最終的には

c1 = {'a','b','c','d'} 
c2 = {'b','c','d'} 
c3 = {'c','d'} 
c_common = my_fun({c1,c2,c3}); 

、私は、c_common={'c','d'}をしたいです。

どうすればMATLABでこれを行うことができますか?事前に

おかげで、

P.S.私はまた、各入力のインデックスが必要ですが、私はおそらく出力c_commonを使用してそれを行うことができますので、答えに必要はありません。この場合の

[c_common, indices] = my_fun({c1,c2,c3}); 

どこindices = {[3,4], [2,3], [1,2]}:誰もが、あまりにもそれに取り組むしたい場合でも、私の実際の出力は次のようになります。この記事に記載されている

おかげで、

+0

File Exchangeでこれを行うためのコードがhttp://www.mathworks.com/matlabcentral/fileexchange/6144-mintersect-multiple-set-intersectionにあるように見えます。 – edwinksl

+0

これは、一対のセルの簡単なシーケンシャルな交差点のように見えますが、著者が指摘しているように、これは特に効率的ではありません。 – edwinksl

+1

@edwinkslありがとう!これはトリックを行い、私の場合効率は非常に大きな懸念ではありません。あなたがこれを回答として投稿したいのであれば、私は受け入れます。もう一度ありがとう:) – jeff

答えて

4

は私たちにuniqueaccumarrayを使用して、共通の文字列とインデックスを与えるためにベクトル化アプローチです。これは、文字列が各セル配列内でソートされていない場合でも、そのセル配列内の位置に対応するインデックスを与えますが、それらは一意でなければなりません。このような場合を見るには、サンプル入力、出力セクション*を見てください。ここでの実装です -

C = {c1,c2,c3}; % Add more cell arrays here 

% Get unique strings and ID each of the strings based on their uniqueness 
[unqC,~,unqID] = unique([C{:}]); 

% Get count of each ID and the IDs that have counts equal to the number of 
% cells arrays in C indicate that they are present in all cell arrays and 
% thus are the ones to be finally selected 
match_ID = find(accumarray(unqID(:),1)==numel(C)); 
common_str = unqC(match_ID) 

% ------------ Additional work to get indices ---------------- 

N_str = numel(common_str); 

% Store matches as a logical array to be used at later stages 
matches = ismember(unqID,match_ID); 

% Use ismember to find all those indices in unqID and subtract group 
% lengths from them to give us the indices within each cell array 
clens = [0 cumsum(cellfun('length',C(1:end-1)))]; 
match_index = reshape(find(matches),N_str,[]); 

% Sort match_index along each column based on the respective unqID elements 
[m,n] = size(match_index); 
[~,sidx] = sort(reshape(unqID(matches),N_str,[]),1); 
sorted_match_index = match_index(bsxfun(@plus,sidx,(0:n-1)*m)); 

% Subtract cumulative group lens to give us indices corres. to each cell array 
common_idx = bsxfun(@minus,sorted_match_index,clens).' 

match_IDを求めるステップであることに注意してください:accumarray(unqID(:),1)histc(unqID,1:max(unqID))置き換えることができます。また、histcountsもあります。

*サンプル入力、出力 -

c1 = 
    'a' 'b' 'c' 'd' 
c2 = 
    'b' 'c' 'a' 'd' 
c3 = 
    'c' 'd' 'a' 
common_str = 
    'a' 'c' 'd' 
common_idx = 
    1  3  4 
    3  2  4 
    3  1  2 
2

をこの質問へのコメントで述べたように、と呼ばれるファイル交換でファイルがある「MINTERSECT - 。複数の積集合は」 を複数のセットに一般化する簡単なコードを含むhttp://www.mathworks.com/matlabcentral/fileexchange/6144-mintersect-multiple-set-intersectionにあります。一言で言えば、このコードは、最初のセルペアでintersectを実行してから出力を取得し、次のセルでこの出力でintersectを実行します。このプロセスは、すべてのセルが比較されるまで続きます。著者は、コードが特に効率的ではないことを指摘していますが、ユースケースでは十分かもしれません。

関連する問題