【问题标题】:MATLAB: comparison of cell arrays of stringMATLAB:字符串元胞数组的比较
【发布时间】:2011-03-14 23:31:06
【问题描述】:

我有两个字符串元胞数组,我想检查它们是否包含相同的字符串(它们的顺序不必相同,我们也不知道它们是否具有相同的长度)。

例如:

a = {'2' '4' '1' '3'};
b = {'1' '2' '4' '3'};

a = {'2' '4' '1' '3' '5'};
b = {'1' '2' '4' '3'};

首先我想到了strcmp,但它需要遍历一个单元格内容并与另一个单元格内容进行比较。我还考虑了ismember,使用类似:

ismember(a,b) & ismember(b,a)

但是我们事先并不知道它们的长度相同(显然是不相等的情况)。那么如何在不编写太多 if/else 案例的情况下以最有效的方式进行这种比较。

【问题讨论】:

    标签: matlab string comparison vectorization cell-array


    【解决方案1】:

    看看函数intersect

    MATLAB 帮助内容:

    [c, ia, ib] = intersect(a, b) 也 返回列索引向量 iaib 这样c = a(ia)b(ib)(或c = a(ia,:)b(ib,:)).

    【讨论】:

    • 我不知道如何从intersect的结果中得到解决方案
    • 这取决于你到底要做什么。如果您需要两个向量都包含相同字符串的标量布尔值,那么 gnovice 的解决方案就是您的正确答案。
    【解决方案2】:

    您可以使用函数SETXOR,它将返回不在两个元胞数组交集中的值。如果它返回一个空数组,那么这两个元胞数组包含相同的值:

    arraysAreEqual = isempty(setxor(a,b));
    



    编辑:一些性能指标...

    由于您对性能指标感到好奇,我想我会根据Amro 列出的两个解决方案(使用ISMEMBERSTRCMP/CELLFUN)来测试我的解决方案的速度。我首先创建了两个大型元胞数组:

    a = cellstr(num2str((1:10000).'));  %'# A cell array with 10,000 strings
    b = cellstr(num2str((1:10001).'));  %'# A cell array with 10,001 strings
    

    接下来,我将每个解决方案运行 100 次以获得平均执行时间。然后,我交换了ab 并重新运行它。结果如下:

        Method     |      Time     |  a and b swapped
    ---------------+---------------+------------------
    Using SETXOR   |   0.0549 sec  |    0.0578 sec
    Using ISMEMBER |   0.0856 sec  |    0.0426 sec
    Using STRCMP   |       too long to bother ;)
    

    请注意,SETXOR 解决方案始终保持快速计时。如果a 包含不在b 中的元素,ISMEMBER 解决方案实际上会运行得稍快一些。这是因为short-circuit && 跳过了计算的后半部分(因为我们已经知道ab 不包含相同的值)。但是,如果a 中的所有值也在b 中,则ISMEMBER 的解决方案会明显变慢。

    【讨论】:

    • 要衡量性能,您需要另一个解决方案进行比较,例如您使用循环和STRCMP 提出的建议。我想性能会非常好,但是如果您发现SETXOR 的使用确实最终成为您处理中的瓶颈,您可以尝试查看其源代码(type setxoredit setxor)并重写通过修剪一些错误检查等来实现。
    • 谢谢,我想我明白@Mikhail 想要做什么了。性能呢?当我只需要一个真/假类型的答案时,似乎两组的 XOR 是一项昂贵的操作
    【解决方案3】:

    您仍然可以像稍作修改一样使用 ISMEMBER 函数:

    arraysAreEqual = all(ismember(a,b)) && all(ismember(b,a))
    

    另外,你可以用 STRCMP 将循环版本写成一行:

    arraysAreEqual = all( cellfun(@(s)any(strcmp(s,b)), a) )
    

    编辑:我正在添加第三个解决方案,改编自另一个SO question

    g = grp2idx([a;b]);
    v = all( unique(g(1:numel(a))) == unique(g(numel(a)+1:end)) );
    

    本着同样的精神,我进行了时间比较(使用TIMEIT函数):

    function perfTests()
        a = cellstr( num2str((1:10000)') );            %#' fix SO highlighting
        b = a( randperm(length(a)) );
    
        timeit( @() func1(a,b) )
        timeit( @() func2(a,b) )
        timeit( @() func3(a,b) )
        timeit( @() func4(a,b) )
    end
    
    function v = func1(a,b)
        v = isempty(setxor(a,b));                      %# @gnovice answer
    end
    
    function v = func2(a,b)
        v = all(ismember(a,b)) && all(ismember(b,a));
    end
    
    function v = func3(a,b)
        v = all( cellfun(@(s)any(strcmp(s,b)), a) );
    end
    
    function v = func4(a,b)
        g = grp2idx([a;b]);
        v = all( unique(g(1:numel(a))) == unique(g(numel(a)+1:end)) );
    end
    

    和函数顺序相同的结果(越低越好):

    ans =
         0.032527
    ans =
         0.055853
    ans =
           8.6431
    ans =
         0.022362
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-03
      • 1970-01-01
      • 2011-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多