计算字符串和重新标记的出现次数

时间:2014-12-29 02:33:03

标签: string matlab count rename

我有一个包含类似内容的n x 1单元格:

chair
chair
chair
chair
table
table
table
table
bike
bike
bike
bike
pen
pen
pen
pen
chair
chair
chair
chair
table
table
etc.

我想重命名这些元素,以便它们能够反映到那时为止的出现次数。输出应如下所示:

chair_1
chair_2
chair_3
chair_4
table_1
table_2
table_3
table_4
bike_1
bike_2
bike_3
bike_4
pen_1
pen_2
pen_3
pen_4
chair_5
chair_6
chair_7
chair_8
table_5
table_6
etc.

请注意短划线(_)是必要的任何人都可以帮忙吗?谢谢。

4 个答案:

答案 0 :(得分:1)

有趣的问题!这是我尝试的程序:

  1. 使用unique - 特别是第三个输出参数,将单元格数组中的每个字符串指定为唯一ID。
  2. 初始化一个空数组,然后创建一个for循环,该循环遍历每个唯一字符串 - 由unique的第一个输出给出 - 并创建一个数字序列,从1到最多我们遇到过这个字符串。将此数字序列放在我们找到每个字符串的相应位置。
  3. 使用strcat将步骤2中创建的数组中的每个元素附加到问题中的每个单元格数组元素。
  4. 第1步

    假设您的单元格数组被定义为存储在A中的一串字符串,我们会以这种方式调用unique

    [names, ~, ids] = unique(A, 'stable');
    

    'stable'非常重要,因为分配给每个唯一字符串的ID都是,而不是按字母顺序重新排序元素,这对于完成工作非常重要。 names将存储数组A中的唯一名称,而ids将包含遇到的每个字符串的唯一ID。对于您的示例,这是namesids的含义:

    names = 
    
        'chair'
        'table'
        'bike'
        'pen'
    
    
    ids =
    
         1
         1
         1
         1
         2
         2
         2
         2
         3
         3
         3
         3
         4
         4
         4
         4
         1
         1
         1
         1
         2
         2
    
    此算法实际上不需要

    names。但是,我已在此处显示,因此您可以看到unique的工作原理。此外,ids非常有用,因为它为遇到的每个字符串分配唯一的ID。因此,chair会被分配ID 1,然后table被分配ID为2,等等。这些ID非常重要,因为我们将使用这些ID来查找每个唯一ID的确切位置找到字符串,以便我们可以分配您想要的线性数值范围。这些位置将存储在下一步计算的数组中。

    步骤#2

    让我们预先分配这个数组以提高效率。我们称之为loc。然后,您的代码看起来像这样:

    loc = zeros(numel(A), 1);
    for idx = 1 : numel(names)
        id = find(ids == idx);
        loc(id) = 1 : numel(id);
    end
    

    因此,对于我们找到的每个唯一名称,我们会查找ids数组中与找到的此特定名称匹配的每个位置。 find将帮助我们在ids中找到与特定名称匹配的位置。一旦找到这些位置,我们只需在loc中为这些位置指定一个增加的线性序列,从1到多个名称。您示例中的loc输出为:

    loc =
    
         1
         2
         3
         4
         1
         2
         3
         4
         1
         2
         3
         4
         1
         2
         3
         4
         5
         6
         7
         8
         5
         6
    

    请注意,这与您所需输出的数字序列(每个字符串的最右边部分)相对应。

    步骤#3

    现在我们所要做的就是将loccell数组中的每个字符串放在一起。因此我们会这样做:

    out = strcat(A, '_', num2str(loc));
    

    这样做是它将A中的每个元素连接起来,连接一个_字符,然后将相应的数字附加到A中每个元素的末尾。因为我们要输出字符串,所以您需要将loc中存储的数字转换为字符串。为此,您必须使用num2strloc中的每个数字转换为相应的字符串等效值。找到这些后,您可以将loc中的每个数字与A中的每个元素(当然都带有_字符)连接起来。输出存储在out中,因此得到:

    out = 
    
    'chair_1'
    'chair_2'
    'chair_3'
    'chair_4'
    'table_1'
    'table_2'
    'table_3'
    'table_4'
    'bike_1'
    'bike_2'
    'bike_3'
    'bike_4'
    'pen_1'
    'pen_2'
    'pen_3'
    'pen_4'
    'chair_5'
    'chair_6'
    'chair_7'
    'chair_8'
    'table_5'
    'table_6'
    

    为了您的复制和粘贴乐趣,这是完整的代码。请注意,我已经排除了unique的第一个输出,因为我们根据您的输出不需要它:

    [~, ~, ids] = unique(A, 'stable');
    loc = zeros(numel(A), 1);
    for idx = 1 : numel(names)
        id = find(ids == idx);
        loc(id) = 1 : numel(id);
    end
    out = strcat(A, '_', num2str(loc));
    

答案 1 :(得分:1)

如果你想要替代unique,你可以使用哈希表,在Matlab中需要使用containers.Map对象。然后,您可以存储每个单独标签的出现次数并随时创建新标签,如下面的代码所示。

data={'table','table','chair','bike','bike','bike'};
map=containers.Map(data,zeros(numel(data),1)); % labels=keys, counts=values (zeroed)
new_data=data; % initialize matrix that will have outputs
for ii=1:numel(data)
    map(data{ii}) = map(data{ii})+1; % increment counts of current labels
    new_data{ii} = sprintf('%s_%d',data{ii},map(data{ii})); % format outputs
end

答案 2 :(得分:1)

这类似于rayryeng's answer,但用bsxfun替换了for循环。在将字符串缩减为唯一标签(下面的代码第1行)之后,应用bsxfun来创建所有(可能重复的)标签之间的成对比较矩阵。保持只有较低的一半"该矩阵和沿行的求和给出了每个标签先前出现的次数(第2行)。最后,这将附加到每个原始字符串(第3行)。

让您的单元格字符串数组表示为c

[~, ~, labels] = unique(c); %// transform each string into a unique label
s = sum(tril(bsxfun(@eq, labels, labels.')), 2); %'// accumulated occurrence number
result = strcat(c, '_', num2str(x)); %// build result

或者,第二行可以用更高效的内存替换

n = numel(labels);
M = cumsum(full(sparse(1:n, labels, 1)));
s = M((1:n).' + (labels-1)*n);

答案 3 :(得分:0)

我会给你一个伪代码,自己试试,如果代码不能发布代码

Initiate a counter to 1
Iterate over the cell
If counter > 1 check with previous value if the string is same
    then increment counter
else
    No- reset counter to 1
end
sprintf the string value + counter into a new array

希望这有帮助!