2016-06-19 10 views
3

Ich möchte die gemeinsamen Elemente in mehreren Arrays (> = 2) von Strings finden. Eine ähnliche Frage ist here, und die Antwort schlägt vor, die Funktion intersect() zu verwenden, jedoch funktioniert es nur für 2 Eingänge.Wie finden Sie gemeinsame Elemente in String-Zellen?

In meinem Fall habe ich mehr als zwei Zellen, und ich möchte eine einzige gemeinsame Teilmenge erhalten. Hier ist ein Beispiel dafür, was ich erreichen möchte:

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

am Ende möchte ich c_common={'c','d'}, da nur diese beiden Strings in allen Eingängen auftreten.

Wie kann ich dies mit MATLAB tun?

Vielen Dank im Voraus,

P. S. Ich brauche auch die Indizes von jedem Eingang, aber ich kann das wahrscheinlich selbst mit der Ausgabe c_common tun, also nicht notwendig in der Antwort. Aber wenn jemand will, dass auch in Angriff zu nehmen, wird meine tatsächliche Ausgabe wie folgt sein:

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

wo indices = {[3,4], [2,3], [1,2]} für diesen Fall. mit unique und accumarray

Danke,

+0

Sieht aus, als gäbe es einen Code, um dies unter File Exchange unter http://www.mathworks.com/matlabcentral/fileexchange/6144-mintersect-multiple-se-intersection zu tun. – edwinksl

+0

Es sieht aus wie eine direkte sequentielle Schnittpunkt eines Paares von Zellen, aber das ist nicht besonders effizient, wie der Autor auch festgestellt. – edwinksl

+1

@edwinksl Vielen Dank! Das macht den Trick, und für meinen Fall ist Effizienz kein großes Problem. Also, wenn Sie dies als Antwort posten möchten, werde ich akzeptieren. Nochmals vielen Dank :) – jeff

Antwort

4

in diesem Beitrag nicht gelistet ist ein vektorisiert Ansatz uns die gemeinsamen Strings und Indizes zu geben. Dies würde auch funktionieren, wenn die Strings nicht innerhalb jedes Zellen-Arrays sortiert sind, um uns Indizes zu geben, die ihren Positionen darin entsprechen, sondern sie müssen eindeutig sein. Sehen Sie sich bitte den Beispieleingabe-, Ausgabeabschnitt * an, um einen solchen Fall zu sehen. Hier ist die Umsetzung -

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).' 

Bitte beachten Sie, dass bei dem Schritt, die match_ID berechnet: accumarray(unqID(:),1) durch histc(unqID,1:max(unqID)) ersetzt werden könnte. Auch histcounts wird dort eine andere Alternative sein.

* Muster Eingang, Ausgang -

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

Wie auf diese Frage in den Kommentaren erwähnt, gibt es eine Datei in File Exchange namens "MINTERSECT -. Mehrere Satz Kreuzung" um http://www.mathworks.com/matlabcentral/fileexchange/6144-mintersect-multiple-set-intersection, die einfachen Code enthält, um intersect zu mehreren Sätzen zu verallgemeinern. Kurz gesagt, der Code erhält die Ausgabe von intersect auf dem ersten Paar von Zellen und dann führen intersect auf diesem Ausgang mit der nächsten Zelle. Dieser Prozess wird fortgesetzt, bis alle Zellen verglichen worden sind. Beachten Sie, dass der Autor darauf hinweist, dass der Code nicht besonders effizient ist, aber für Ihren Anwendungsfall ausreichend sein kann.