MATLAB 中用于不等长度单元数组的 strcmp 函数

6
有没有一种简单的方法在较大的字符串单元格数组中找到一个更小的单元格数组? 我有两个列表,一个有唯一元素,另一个有重复元素。 我想找到较大数组中特定模式的完整出现。 我知道 strcmp 可以比较两个单元格数组,但仅当它们长度相等时才能比较。 我首先想到的是使用循环遍历较大数组的子集,但肯定有更好的解决方案。
例如,在以下内容中:
smallcellarray={'string1',...
                'string2',...
                'string3'};
largecellarray={'string1',...
                'string2',...
                'string3',...
                'string1',...
                'string2',...
                'string1',...
                'string2',...
                'string3'};

index=myfunction(largecellarray,smallcellarray)

将返回

index=[1 1 1 0 0 1 1 1]
4个回答

9
您可以使用函数ISMEMBER获取largecellarray中单元格在较小数组smallcellarray中出现的索引向量,然后使用函数STRFIND(适用于字符串和数值数组)查找较小数组在较大数组中的起始索引:
>> nSmall = numel(smallcellarray);
>> [~, matchIndex] = ismember(largecellarray,...  %# Find the index of the 
                                smallcellarray);    %#   smallcellarray entry
                                                    %#   that each entry of
                                                    %#   largecellarray matches
>> startIndices = strfind(matchIndex,1:nSmall)  %# Starting indices where the
                                                %#   vector [1 2 3] occurs in
startIndices =                                  %#   matchIndex

     1     6

然后就是根据这些起始索引构建向量index的问题。下面是一种创建此向量的方法:

>> nLarge = numel(largecellarray);
>> endIndices = startIndices+nSmall;  %# Get the indices immediately after
                                      %#   where the vector [1 2 3] ends
>> index = zeros(1,nLarge);           %# Initialize index to zero
>> index(startIndices) = 1;           %# Mark the start index with a 1
>> index(endIndices) = -1;            %# Mark one index after the end with a -1
>> index = cumsum(index(1:nLarge))    %# Take the cumulative sum, removing any
                                      %#   extra entry in index that may occur
index =

     1     1     1     0     0     1     1     1

使用函数BSXFUN创建它的另一种方法由Amro提供。另一个创建它的方法是:

index = cumsum([startIndices; ones(nSmall-1,numel(startIndices))]);
index = ismember(1:numel(largecellarray),index);

如果 largecellarray{'string3'},那么这样做不会产生正确的结果,对吗? - Jonas
@Jonas:对于这种情况,我使用上面最新版本的解决方案得到了“index = 0”。 - gnovice
哦,现在我明白你的解决方案了。聪明!+1 - Jonas
我曾经用这段代码解决过类似的问题。MATLAB 抱怨 strfind 需要只有一行的输入,所以我改成了这个:startIndices = strfind(matchIndex',1:nSmall') - raggot

5
这是我的版本(基于@yuk和@gnovice的回答):
g = grp2idx([S L])';
idx = strfind(g(numel(S)+1:end),g(1:numel(S)));
idx = bsxfun(@plus,idx',0:numel(S)-1);

index = zeros(size(L));
index(idx(:)) = 1;

很好,尽管有两个事情值得一提:1)您需要统计工具箱才能使用GRP2IDX。 2)函数FINDSTR似乎已经被STRFIND取代,即将过时。 - gnovice
@gnovice:修复了findstr/strfind(注意现在参数的顺序很重要),我没有意识到它是一个已弃用的函数..谢谢。 - Amro

1

在 @gnovice 的回答中,第一部分可以是:

l = grp2idx(largecellarray)';
s = grp2idx(smallcellarray)';
startIndices = strfind(l,s);

我不知道grp2idx。 不错!但是如果largecellarray中有一个“string0”,这样会失败吗? - Jonas
不幸的是,只有当 smallcellarray 中的 N 个条目恰好largecellarray 中的前 N 个条目完全相同时,此方法才有效。 - gnovice
是的,在许多情况下它实际上会失败,因为对于grp2idx顺序很重要。也许ismember函数在这里很重要。 - yuk
如果将它们作为一个单元数组传递给grp2idx,它将解决问题。 - Amro

0

我已经得到以下解决方案,但我仍然想知道是否有更好的方法来做到这一点:

function [output]=cellstrcmpi(largecell,smallcell)
output=zeros(size(largecell));
idx=1;
while idx<=length(largecell)-length(smallcell)+1
    if sum(strcmpi(largecell(idx:idx+length(smallcell)-1),smallcell))==length(smallcell)
       output(idx:idx+length(smallcell)-1)=1;
       idx=idx+length(smallcell);       
    else
        idx=idx+1;
    end
end

(我知道,我知道,没有错误检查 - 我是一个可怕的人。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接