在字符串数组中查找多个列重复项并在MATLAB

时间:2017-10-23 13:38:11

标签: arrays string matlab loops

我有一个2列的字符数组,以及一个长度相同的数字数组。如果两列匹配,那么我想通过删除它们并对数值数组行求和来合并这些行。

例如,如果一行字符串是{'abd','123'}而另一行是{'abd','123'},那么我想要所有这些索引,这样我就可以打印出一个包含3列的CSV文件,前两行是唯一的,第三是重复的总和。

我正在使用MATLAB 2012。

textdata = {'1','3','6','6','12','12','12','4','1'}';
textdata(:,2) = {'c','q','r','r','s','b','s','q','d'}';
nums = [1,4,5,6,7,3,2,23,34]';

所以这和我在csv文件中读到的内容类似,其中2列是char字符串,如'223455'和'23455x',所以我只想尝试复制较小的数据集。而且我正在使用你的解决方法,但就像你说的那样不能在行上工作。

% At = table(A(:,1), A(:,2));
[At2,~,ID] = unique(textdata,'rows');
At2.Var3 = accumarray(ID, nums(:));
% writetable(At2, 'output.csv', 'WriteVariableNames', false);

2 个答案:

答案 0 :(得分:3)

从您的示例中获取数据,让我们这样设置......

myCell = {'1', '3', '6', '6', '12', '12', '12', '4', '1';
          'c', 'q', 'r', 'r', 's',  'b',  's',  'q', 'd'}.';
nums = [1, 4, 5, 6, 7, 3, 2, 23, 34].';

因此,我们要整合'6', 'r'行和'12', 's'行。

现在,如果您的数据全部是数字,我们可以使用unique(myData, 'rows'),但单元数组不支持'rows'。我们可以调用unique一次,reshape结果,然后再次在 indices 上调用unique。由于索引是数字的,我们现在可以使用'rows'

% Get unique strings, use stable so result isn't sorted
% To start with, we are only interested in the indices of duplicate items, didx
[~, ~, didx] = unique(myCell, 'stable'); 
% Reshape back to 2 columns and run unique on the rows
% This time we also save the indices of the unique rows, uidx
[~, uidx, didx] = unique(reshape(didx, [], 2), 'rows', 'stable');

现在,您现在可以使用accumarray和一些连接来获得结果

result = [myCell(uidx, :), num2cell(accumarray(didx, nums))];

>> result =
      { '1'  'c'  1
        '3'  'q'  4
        '6'  'r'  11
        '12' 's'  9
        '12' 'b'  3
        '4'  'q'  23
        '1'  'd'  34 }
% Note how the '6','r' and '12','s' rows have values of 11=6+5 and 9=7+2 respectively

答案 1 :(得分:1)

解决方法是将您的字符串数组转换为表,在此表上使用unique,以便我们可以建立映射到每一行的ID,然后最后使用accumarray执行所需的求和。鉴于您的示例相当有限,让我们说A包含您的字符串数组,B包含您的相同大小的数字数组。

因此:

At = table(A(:,1), A(:,2));
[At2,~,ID] = unique(At);
At2.Var3 = accumarray(ID, B(:));
writetable(At2, 'output.csv', 'WriteVariableNames', false);

第一行代码将您的字符串数组转换为实际表,其中每列是字符串数组中的一列。然后,我们使用unique的第三个输出将表的每一行转换为唯一的整数ID,以便具有相同ID的行表示它们的行内容相等。 unique的第一个输出为我们提供了一个只包含表的唯一行的新表。然后我们使用accumarray,以便我们将具有相同ID的所有行组合在一起,并使用B访问ID提供的这些相应位置,并将这些值相加在一起。这是accumarray的默认行为。 accumarray的输出将与唯一表具有相同的行数,并且顺序使得每个元素为我们提供在一行中共享同一对字符串的那些行的总和。然后,我们在此表中添加一个新列,并将其写入名为output.csv的CSV文件中。我忽略了列标题,在上面的代码中创建table提供了填充列标题,这可能不是您想要的。

作为一个简单示例,假设AB为:

>> A = string({'abd', '123'; 'abd', '123'; 'abcc', '1234'; 'abdef', '34567'})

A = 

  4×2 string array

    "abd"      "123"  
    "abd"      "123"  
    "abcc"     "1234" 
    "abdef"    "34567"

>> B = [3; 4; 6; -1]

B =

     3
     4
     6
    -1

运行上面的代码给出了下表:

>> At2

At2 = 

     Var1       Var2      Var3
    _______    _______    ____

    "abcc"     "1234"      6  
    "abd"      "123"       7  
    "abdef"    "34567"    -1  

我们可以看到每一行给出了从字符串数组共享相同位置的所有数值的总和。此矩阵的前两行具有相同的字符串对,因此它们对应的值3和4将添加到7.您可以自己验证表的其余部分。