2011-11-06 250 views
3

我有以下形式的两个阵列:MATLAB:条件求和

v1 = [ 1 2 3 4 5 6 7 8 9 ... ] 
c2 = { 'a' 'a' 'a' 'b' 'b' 'c' 'c' 'c' 'c' ... } 

(所有数值仅是示例,没有图案可以假定在真实数据v1c2具有相同的尺寸。)

我想获得一个向量,其中包含对应于c2中相同值的v1组件的总和。在上面的示例中,结果向量的第一个分量是1+2+3,第二个分量是4+5,依此类推。

我知道我可以在形式的循环做到这一点:

uni_c2 = unique(c2); 
result = zeros(size(uni_c2)); 
for i = 1:numel(uni_c2) 
    result(i) = sum(v1(strcmp(uni_c2(i),c2))); 
end 

是否有一个命令或做同样的操作方式矢量?

+0

”v1的分量的总和对应于c2中的相等值“。 c2中的连续值?例如:v1 = [1 2 3 4],c2 = ['a','b','a','a'],在这个例子中你期望的结果是什么? –

回答

3

可以在两行执行此操作:

[b, m, n] = unique(c2) 
result = accumarray(n', v1) 

结果的元素对应于在单元阵列b中的字符串。 “

+0

太好了,@Carl,正是我在找的东西。唯一的问题是,根据我的测试,'n'必须转换为列向量:'result = accumarray(n',v1)'。感谢您的帮助。 – foglerit

+0

感谢您的修复。我家里没有Matlab,所以我无法测试我的代码。我会编辑我的答案 –

1

这是矢量化的,但对于非常大的矢量来说是个坏主意。对于某些问题,“向量化”解决方案比for循环更差。

>> v1 = [ 1 2 3 4 5 6 7 8 9]; 
>> c2 = 'aaabbcccc'-'a' 
c2 = 
    0 0 0 1 1 2 2 2 2 
>> N = repmat(c2',1,max(c2)-min(c2)+1) == repmat([min(c2):max(c2)],size(c2,2),1); 
>> v1*N 
ans = 
    6 9 30 
+0

非常巧妙,@stardt!这是因为像这样的宝石,我喜欢网络上的矢量化问题。但是你的解决方案使用的假设是c2遵循问题中的模式,当时这只是一个简化的例子(如上所述)。实际上,我的单​​元格内容更加复杂和难以预测。关于如何推广您的方法的任何想法? – foglerit

+0

@jonnat代码不依赖于模式。它适用于例如'c2 ='abacaccbc' - 'a''你真正的问题与什么假设相矛盾? – stardt

+0

我的c2实际上包含的元素不是单个字母。我选择使用单字母元素作为简化。 – foglerit

0

我觉得很一般(和矢量)解决方案是这样的:

v1 = [ 1 2 3 4 5 6 7 8 9 ] 
c2 = { 'a' 'a' 'a' 'b' 'b' 'c' 'c' 'c' 'c' } 
uniqueValuesInC2 = unique(c2); 
conditionalSumOfV1 = @(x)(sum(v1(strcmp(c2, x)))); 
result = cellfun(conditionalSumOfV1, uniqueValuesInC2) 

也许我的解决方案需要一点解释给未经训练的眼睛:

所以首先你实际上需要计算c2中的不同可能值,这由unique完成。

conditionalSumOfV1函数需要一个参数x,它在每c2比较元素与x和在v1选择相应的元件和对其求和。

最后cellfun比得上在一些其他语言foreach构建体:函数conditionalSum为单元阵列你提供在每一个值进行评估(在这种情况下:在c2每个唯一的值),并将其存储在输出数组英寸对于其他类型的容器变量(数组,结构体),MATLAB具有等效的foreach样构造:arrayfun,structfun

这将适用于比单个字符长的c2的内容,并且它不需要大的repmat操作作为stardt的解决方案。但是,当涉及到长阵列时,我的确怀有疑问,其中c2只有一些重复值,但我想对大多数算法来说这将是一个难题。如果你是在这种情况下,你可能需要看看的unique额外的输出或编写自己的替代unique(即写for循环,最好是编译型语言/ MEX)。