如何在字符串单元格中找到常用元素?

时间:2016-06-19 20:30:46

标签: string matlab cell-array set-intersection

我想找到多个(> = 2)字符串单元格数组中的公共元素。

相关问题是here,答案建议使用函数intersect(),但它仅适用于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]}

谢谢,

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:2)

正如对此问题的评论中所述,文件交换中有一个名为" MINTERSECT - 多集交集的文件。"在http://www.mathworks.com/matlabcentral/fileexchange/6144-mintersect-multiple-set-intersection,其中包含将intersect概括为多个集合的简单代码。简而言之,代码从第一对单元格上的intersect执行输出,然后在下一个单元格的输出上执行intersect。这个过程一直持续到比较所有细胞。请注意,作者指出代码不是特别有效,但对于您的用例可能就足够了。