我有一个包含类似内容的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.
请注意短划线(_)是必要的任何人都可以帮忙吗?谢谢。
答案 0 :(得分:1)
有趣的问题!这是我尝试的程序:
unique
- 特别是第三个输出参数,将单元格数组中的每个字符串指定为唯一ID。for
循环,该循环遍历每个唯一字符串 - 由unique
的第一个输出给出 - 并创建一个数字序列,从1到最多我们遇到过这个字符串。将此数字序列放在我们找到每个字符串的相应位置。strcat
将步骤2中创建的数组中的每个元素附加到问题中的每个单元格数组元素。假设您的单元格数组被定义为存储在A
中的一串字符串,我们会以这种方式调用unique
:
[names, ~, ids] = unique(A, 'stable');
'stable'
非常重要,因为分配给每个唯一字符串的ID都是,而不是按字母顺序重新排序元素,这对于完成工作非常重要。 names
将存储数组A
中的唯一名称,而ids
将包含遇到的每个字符串的唯一ID。对于您的示例,这是names
和ids
的含义:
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的确切位置找到字符串,以便我们可以分配您想要的线性数值范围。这些位置将存储在下一步计算的数组中。
让我们预先分配这个数组以提高效率。我们称之为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
请注意,这与您所需输出的数字序列(每个字符串的最右边部分)相对应。
现在我们所要做的就是将loc
与cell
数组中的每个字符串放在一起。因此我们会这样做:
out = strcat(A, '_', num2str(loc));
这样做是它将A
中的每个元素连接起来,连接一个_
字符,然后将相应的数字附加到A
中每个元素的末尾。因为我们要输出字符串,所以您需要将loc
中存储的数字转换为字符串。为此,您必须使用num2str
将loc
中的每个数字转换为相应的字符串等效值。找到这些后,您可以将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
希望这有帮助!