19

我有一个向量,例如

vector = [1 2 3]

我想在自身内复制它n 次,即如果 n = 3,它最终会变成:

vector = [1 2 3 1 2 3 1 2 3]

对于任何 n 值,我怎样才能实现这一点?我知道我可以做到以下几点:

newvector = vector;
for i = 1 : n-1
    newvector = [newvector vector];
end

不过这似乎有点麻烦。还有更有效的方法吗?

4

3 回答 3

39

尝试

repmat([1 2 3],1,3)

我会让你检查文档repmat

于 2012-04-25T12:59:34.417 回答
20

这是一种比repmatreshape一个数量级更快的方法

做这些事情的最好方法之一是使用托尼的技巧。通常发现 Repmat 和 Reshape 比 Tony 的技巧慢,因为它直接使用 Matlabs 固有索引。回答你的问题,

可以说,您想平铺行向量r=[1 2 3] N时间,例如r=[1 2 3 1 2 3 1 2 3...]

c=r'
cc=c(:,ones(N,1));
r_tiled = cc(:)';

对于大型's reshape,此方法可显着节省时间。repmatN

编辑:回复@Li-aung Yip 的疑问

repmat我进行了一个小的 Matlab 测试来检查和之间的速度差异tony's trick。使用下面提到的代码,我计算了从基向量构造相同平铺向量的时间A=[1:N]。结果表明,是的,Tony's-Trick 的速度快了一个数量级,尤其是对于较大的 N。欢迎大家自己尝试。如果必须在循环中执行这样的操作,那么这么大的时间差可能很关键。这是我使用的小脚本;

N= 10 ;% ASLO Try for values N= 10, 100, 1000, 10000

% time for tony_trick
tic;
A=(1:N)';
B=A(:,ones(N,1));
C=B(:)';
t_tony=toc;
clearvars -except t_tony N

% time for repmat
tic;
A=(1:N);
B=repmat(A,1,N);
t_repmat=toc;
clearvars -except t_tony t_repmat N

下面给出了两种方法的时间(以秒为单位);

  • N=10,time_repmat = 8e-5,time_tony = 3e-5
  • N=100,time_repmat = 2.9e-4,time_tony = 6e-5
  • N=1000,time_repmat = 0.0302,time_tony = 0.0058
  • N=10000,time_repmat = 2.9199,time_tony = 0.5292

我的 RAM 不允许我超过 N=10000。我敢肯定,对于 N=100000,这两种方法之间的时间差异会更加显着。我知道,对于不同的机器,这些时间可能会有所不同,但是时间数量级的相对差异会保持不变。此外,我知道,平均时间可能是一个更好的指标,但我只是想显示两种方法之间时间消耗的数量级差异。我的机器/操作系统详细信息如下:

相关机器/操作系统/Matlab 详细信息:Athlon i686 Arch,Ubuntu 11.04 32 位,3gb ram,Matlab 2011b

于 2012-04-26T05:18:51.550 回答
4

根据 Abhinav 的回答和一些测试,我编写了一个总是比 repmat() 快的函数!

它使用相同的参数,除了第一个参数必须是向量而不是矩阵。

function vec = repvec( vec, rows, cols )
%REPVEC Replicates a vector.
%   Replicates a vector rows times in dim1 and cols times in dim2.
%   Auto optimization included.
%   Faster than repmat()!!!
%   
%   Copyright 2012 by Marcel Schnirring

    if ~isscalar(rows) || ~isscalar(cols)
        error('Rows and cols must be scaler')
    end

    if rows == 1 && cols == 1
        return  % no modification needed
    end

    % check parameters
    if size(vec,1) ~= 1 && size(vec,2) ~= 1
        error('First parameter must be a vector but is a matrix or array')
    end

    % check type of vector (row/column vector)
    if size(vec,1) == 1
        % set flag
        isrowvec = 1;
        % swap rows and cols
        tmp = rows;
        rows = cols;
        cols = tmp;
    else
        % set flag
        isrowvec = 0;
    end

    % optimize code -> choose version
    if rows == 1
        version = 2;
    else
        version = 1;
    end

    % run replication
    if version == 1
        if isrowvec
            % transform vector
            vec = vec';
        end

        % replicate rows
        if rows > 1
            cc = vec(:,ones(1,rows));
            vec = cc(:);
            %indices = 1:length(vec);
            %c = indices';
            %cc = c(:,ones(rows,1));
            %indices = cc(:);
            %vec = vec(indices);
        end

        % replicate columns
        if cols > 1
            %vec = vec(:,ones(1,cols));
            indices = (1:length(vec))';
            indices = indices(:,ones(1,cols));
            vec = vec(indices);
        end

        if isrowvec
            % transform vector back
            vec = vec';
        end
    elseif version == 2
        % calculate indices
        indices = (1:length(vec))';

        % replicate rows
        if rows > 1
            c = indices(:,ones(rows,1));
            indices = c(:);
        end

        % replicate columns
        if cols > 1
            indices = indices(:,ones(1,cols));
        end

        % transform index when row vector
        if isrowvec
            indices = indices';
        end

        % get vector based on indices
        vec = vec(indices);
    end
end

随意使用您的所有数据测试该功能并给我反馈。当你发现一些可以改进的地方时,请告诉我。

于 2012-08-26T18:06:05.677 回答