【问题标题】:find repetition cell array查找重复元胞数组
【发布时间】:2013-11-21 15:17:50
【问题描述】:

我有一个类似的单元格数组

 A = {'hello'; 2; 3; 4; 'hello';2;'hello'}

我想查找此数组中是否有重复项并确定它们的名称和索引。 在这个例子中,我想要这样的东西:

names = {'hello';2};
indexes = [1, 5, 7;
         2, 6, 0];

我已将第二行索引的最后一个元素设置为 0,只是为了在维度上没有问题...我的问题是元胞数组既是 char 又是 double...我不知道如何处理这个...

【问题讨论】:

  • 将所有条目转换为字符串是否可以接受?如果你的 A{'2';2} 会发生什么?
  • 是的,在我的特殊情况下它是可能的......我想知道是否存在一个通用的解决方案......无论如何,如果你有这个解决方案,它非常受欢迎:)

标签: matlab cell


【解决方案1】:

乱七八糟,不过可以搞定:

m = max(cellfun(@length, A));
A2 = cellfun(@(e) [double(e) inf(1,m-length(e)) ischar(e)], A, 'uni' ,false);
A2 = cell2mat(A2);
[~, ~, jj] = unique(A2,'rows');
num = accumarray(jj,1,[],@numel);
[~, kk] = max(bsxfun(@eq, jj, find(num>1).'));
names = A(kk);
indices = arrayfun(@(n) find(jj==jj(kk(n))), 1:length(kk), 'uni', false);

这是如何工作的A2 只是将A 转换为数字矩阵。每行代表A的一个条目,最后一列用作区分原始数字和原始字符串的标志,inf用作填充符。然后通常的一对uniqueaccumarray 做实际的工作,结果是从jjnum 得到一些比较和索引。

【讨论】:

  • 未定义函数或变量 'bb'。你是说kk?
  • 虽然答案有点笨拙(我觉得可以更轻松地完成),但这是uniqueaccumarray 一起发挥作用的另一个例子! :-) @chappjc
  • 有点难以理解,尤其是对于那些并不真正了解优化方法的人,例如bsxfuncellfun,但仍然是一个有效的解决方案。
  • @MZimmerman6 我同意。在我写完之后,我也很难理解 :-D 正如我上面所说的,这可能是一种笨拙的方式。我有一种感觉,按照这种方法,它可以做得更好;特别是unique 之后的行
【解决方案2】:

因为您使用的是包含字符串和数字的结构,所以事情并不那么容易。假设您根本无法更改这一点,查找唯一值及其索引的最佳方法是循环遍历指定的元胞数组,并将其内容保存到地图对象中,该对象将存储这些唯一条目存在的索引。

这对于 MATLAB 的 map 结构非常简单,可以按照下面的代码进行。

A = {'hello'; 2; 3; 4; 'hello';2;'hello'}

cellMap = containers.Map();
for i = 1 : numel(A)
    mapKey = num2str(A{i});
    if cellMap.isKey(mapKey)
       tempCell = cellMap(mapKey);
       tempCell{numel(tempCell)+1} = i;
       cellMap(mapKey) = tempCell;
    else
        tempCell = cell(1);
        tempCell{1} = i;
        cellMap(mapKey) = tempCell;
    end
end

您可以通过输入cellMap.keys 找到所有唯一值,这将返回

ans = 
    '2'    '3'    '4'    'hello'

然后您可以使用这些键通过cellMap('hello') 找出它们在原始数组中出现的位置。

ans = 
    [1]    [5]    [7]

完成所有这些后,您可以进行一些转换以恢复原始状态并将内容更多地转换为您想要的格式。

uniqueVals = cellMap.keys;
uniqueIndices = cell(1,numel(uniqueVals));
for i = 1:numel(uniqueVals)
    uniqueIndices{i} = cell2mat(cellMap(uniqueVals{i}));
      numEquiv = str2double(uniqueVals{i});
      if ~isnan(numEquiv)
          uniqueVals{i} = numEquiv;
      end
end
uniqueVals{4}
uniqueIndices{4}

将返回:

ans =
    hello
ans = 
    1     5     7

另一种选择,可能更简单直接,就是复制您的元胞数组,并将其所有内容转换为字符串格式。这不会立即以您想要的格式返回内容,但它是一个开始

B = cell(size(A));
for i = 1:numel(A)
    B{i} = num2str(A{i});
end
[C,~,IC] = unique(B)

然后您可以使用来自unique 的返回来查找索引,但老实说,这一切都已经通过我上面编写的映射代码完成了。

【讨论】:

    【解决方案3】:

    这是一个更优雅的解决方案(而且更简单!):

    %// Find repeating cells
    A = A(:);        %// Make sure it's a column array
    ia = 1:numel(A);
    tf = sortrows(bsxfun(@(m, n)cellfun(@isequal, A(m), A(n)), ia, ia(:)));
    tf = tf(any(diff([zeros(size(ia)); tf]), 2) & sum(tf, 2) > 1, :);
    
    %// Extract corresponding indices and values
    indices = arrayfun(@(x){find(tf(x, :))}, 1:size(tf, 1));
    names = cellfun(@(x)A(x(1)), indices);
    

    此解决方案适用于任何数据,而不仅仅是字符串和数字。

    示例

    如果我们运行这个:

    A = {'hello'; 2; 3; 4; 'hello'; 2; 'hello'; 4}
    

    我们得到:

    indices =
         [4   8]
         [2   6]
         [1   5   7]
    
    names = 
        4
        2
        'hello'
    

    【讨论】:

    • 它绝对看起来比我的解决方案更好。但是sortwors 行给了我一个错误(Matlab 2010b):???使用 ==> cellfun 时出错所有输入参数的大小和形状必须相同。先前的输入在维度 1 中的大小为 1。输入 #3 的大小为 8。==> @(m,n)cellfun(@isequal,A(m),A(n)) 中的错误
    • 我认为 sortrows 是在 2012a 或 b 中添加的
    • @MZimmerman6 我确实有sortrows,但它给了我这个错误
    • 我会调查的。我在 Octave 上进行了测试,因为我手头没有 MATLAB。
    猜你喜欢
    • 2015-04-23
    • 2013-10-27
    • 2012-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多