在Matlab中,我们有这样的场景:
v =[1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 .... N N N N];
其中v中的元素总是按从1到N的递增顺序,我们知道N的值。我们想计算"1"one_answers"2"的个数。。。v.
当然,我们可以使用如下循环:
for i = 1 : N
% method A
tic
ind = find(v == i)
---> do sth with ind
t1 = toc;
% method B
tic
ind = v(v == i)
---> do sth with ind
t2 = toc;
% method C
tic
ind = ismember(v , i)
---> do sth with ind
t3 = toc;
end
这些方法中每种方法所花费的时间大致等于$t1=0.02 sec$、$t2=0.02 sec$和$t3=0.03 sec$。在我的实际工作中,N是巨大的,整个循环需要2-3个小时!
你有什么想法可以增加这个过程的时间吗?任何想法都值得赞赏。
特定情况:排序输入,仅计数
如果你想得到计数,这里可以建议一些方法。
方法#1:
accumarray(v(:),1)
方法#2:
diff([0 find([diff(v) 1])])
方法#3:
histc(v,1:max(v))
对于性能,我会在diff
上下注,然后在accumarray
上下注,最后在histc
上下注。
一般情况:未排序输入,计数&指数
对于输入向量v
未排序的一般情况,您可能还需要对应于每组相同数字的索引,这里有一种将索引存储在单元阵列中的方法-
[~,sort_idx] = sort(v);
sorted_v = v(sort_idx);
counts = diff([0 find([diff(sorted_v) 1])])
indices_per_grp = mat2cell(sort_idx,1,counts);
样品运行-
v =
2 1 3 3 2 4 1 2 1 1 4 3 4 3
counts =
4 3 4 3
indices_per_grp{1} =
2 7 9 10
indices_per_grp{2} =
1 5 8
indices_per_grp{3} =
3 4 12 14
indices_per_grp{4} =
6 11 13
我偏爱这里的bsxfun
:
counts = sum(bsxfun(@eq,v(:),1:max(v)));
由于它们是经过排序的,您可以提高效率!
怎么样
lastfound = 1;
for i = 1 : N
% find first location after current pos, where value is i
indStart = find(v(lastfound:end) == i, 1)
% find first location, after this, where value is not i
indEnd = find(v(indStart:end) ~= i, 1)
% now you have the range indStart:indEnd-1
...
lastfound = indEnd; % start next one after the end of the current value
end
即仅从最后找到的项目向前搜索。
我相信find(..., 1)
只找到了第一个项目。