合并不同细胞的元素

时间:2015-07-04 05:56:11

标签: matlab cell

假设我们有一个由id和一个属性组成的单元格数组,例如

A{1,1}=[1 2;2 4]
A{1,2}=[2 3 5;8 5 6] 

现在,我希望最终输出由两个单元格的唯一ID(第一行值)组成,相应的列分别具有每个单元格的属性值。 即

C = 
[1]    [         2]
[2]    [1x2 double]  % 4 in first cell and 8 in second cell
[3]    [         5]
[5]    [         6]

似乎无法使用像C=[unique(A{1,:}(1,:)')]这样的东西。非常感谢任何帮助。

1 个答案:

答案 0 :(得分:4)

假设每个单元格有两行且可变数量的列,其中第一行是ID,第二行是属性,我将所有单元格合并为一个2D矩阵并使用{{ 3}}。 accumarray非常适合此处,因为您希望将属于同一ID的值组合在一起并对其应用函数。在我们的例子中,我们的函数只是将值放在单元格数组中,我们确保对值进行排序,因为每个ID按accumarray分组的值以随机顺序进入函数。

使用accumarray将单元格转换为2D矩阵,对其进行转置以使其与accumarray兼容,然后使用它。我需要注意的一件事是,如果缺少任何ID,accumarray将使此插槽为空。缺少的意思是,在你的例子中,缺少ID 4,因为3和5之间存在差距,并且ID 6介于5和7之间(我在评论中添加了示例)。因为数据中最大的ID是7,accumarray的工作原理是将ID 1到ID 7的输出以1为增量进行分配。我们需要解决的最后一件事是从{的输出中消除任何空单元格。 {1}}完成分组。

顺便说一下,我假设您的单元格数组由一个行的单元格组成,就像您的示例一样....所以:

accumarray

我们得到:

%// Setup
A{1,1}=[1 2;2 4];
A{1,2}=[2 3 5;8 5 6];
A{1,3}=[7;8];

%// Convert row of cell arrays to a single 2D matrix, then transpose for accumarray
B = cell2mat(A).';

%// Group IDs together and ensure they're sorted
out = accumarray(B(:,1), B(:,2), [], @(x) {sort(x)});

%// Add a column of IDs and concatenate with the previous output
IDs = num2cell((1:numel(out)).');
out = [IDs out];

%// Any cells from the grouping that are empty, eliminate
ind = cellfun(@isempty, out(:,2));
out(ind,:) = [];

如果您想在2D单元阵列上完成此操作,其中此单元阵列的每一行代表同一问题的单独实例,我的一个建议是可能遍历每一行。在评论中给出了你的例子:

out = 

    [1]    [         2]
    [2]    [2x1 double]
    [3]    [         5]
    [5]    [         6]
    [7]    [         8]

>> celldisp(out(2,:))

ans{1} =

     2         

ans{2} =

     4
     8

我们得到:

%// Setup
A{1,1}=[1 2;2 4];
A{1,2}=[2 3 5;8 5 6];
A{1,3}=[7;8];
A{2,1}=[1 2;2 4]; 
A{2,2}=[1;7];

%// Make a cell array that will contain the output per row
out = cell(size(A,1),1);

for idx = 1 : size(A,1)
     %// Convert row of cell arrays to a single 2D matrix, then transpose for accumarray
      B = cell2mat(A(idx,:)).';

      %// Group IDs together and ensure they're sorted
      out{idx} = accumarray(B(:,1), B(:,2), [], @(x) {sort(x)});

      %// Add a column of IDs and concatenate with the previous output
      IDs = num2cell((1:numel(out{idx})).');
      out{idx} = [IDs out{idx}];

      %// Any cells from the grouping that are empty, eliminate
      ind = cellfun(@isempty, out{idx}(:,2));
      out{idx}(ind,:) = [];
end