4

更新:私はいくつかのテストを行いました.Jonasのソリューションは、さまざまなサイズの入力ベクトルの範囲で最速です. 特に、Angainor が指摘するように、ソリューションは非常にうまく大きなサイズにスケールアップします。これは重要なテストであり、通常、SO についてこの種の質問を投げかけるのは大きなサイズの問題です。Jonas と tmpearce の両方のソリューションに感謝します。大規模な問題のソリューションの効率に基づいて、Jonas に答えを与えています。

私の質問:私はこの列ベクトルを持っています:

Vec = [0; 1; 2; -1; -3; 0; 0; 2; 1; -1];

1より大きいすべての要素を、要素の値と同じ長さを持つ一連の要素に変換したいと思います。同様に、マイナス 1 未満のすべての要素をマイナス 1 のシーケンスに変換したいと考えています。したがって、私の出力ベクトルは次のようになります。

VecLong = [0; 1; 1; 1; -1; -1; -1; -1; 0; 0; 1; 1; 1; -1];

各 2 は 2 つの 1 に変更され、-3 は 3 つの -1 に変更されていることに注意してください。現在、次のように問題を解決しています。

VecTemp = Vec;
VecTemp(VecTemp == 0) = 1;
VecLong = NaN(sum(abs(VecTemp)), 1);
c = 1;
for n = 1:length(Vec)
    if abs(Vec(n)) <= 1
        VecLong(c) = Vec(n);
        c = c + 1;
    else
        VecLong(c:c + abs(Vec(n))) = sign(Vec(n));
        c = c + abs(Vec(n));
    end    
end

これはあまりエレガントではありません。誰でもより良い方法を提案できますか? 注:Vecには整数値のみが含まれると想定できます。すべての提案を前もって感謝します。

4

2 に答える 2

3

古き良きcumsum-approachを使用して、エントリを適切に繰り返すことができます。すべてを1行にまとめたい場合は、取り除くことができるいくつかの一時変数を割り当てていることに注意してください。

%# create a list of values to repeat
signVec = sign(Vec);

%# create a list of corresponding indices that repeat
%# as often as the value in signVec has to be repeated

tmp = max(abs(Vec),1); %# max: zeros have to be repeated once
index = zeros(sum(tmp),1);
index([1;cumsum(tmp(1:end-1))+1])=1; %# assign ones a pivots for cumsum
index = cumsum(index); %# create repeating indices

%# repeat
out = signVec(index);
out'
out =

     0     1     1     1    -1    -1    -1    -1     0     0     1     1     1    -1
于 2012-10-27T07:24:09.243 に答える
3

編集:別の(少しわかりにくい)がこれを行うためのより短い方法を考えました。それはあなたが持っているループよりも高速です。

for rep=1:100000
    #% original loop-based solution
end
toc
Elapsed time is 2.768822 seconds.

#% bsxfun-based indexing alternative
tic;
for rep=1:100000
TempVec=abs(Vec);TempVec(Vec==0)=1;
LongVec = sign(Vec(sum(bsxfun(@gt,1:sum(TempVec),cumsum(TempVec)))+1))
end
toc
Elapsed time is 1.798339 seconds.

この回答は、元の回答と比較して、少なくともある程度まではかなりうまくスケーリングされます。パフォーマンスのスイート スポットがあります。

Vec = repmat(OrigVec,10,1);
#% test with 100,000 loops
#% loop-based solution:
Elapsed time is 19.005226 seconds.
#% bsxfun-based solution:
Elapsed time is 4.411316 seconds.

Vec = repmat(OrigVer,1000,1);
#% test with 1,000 loops - 100,000 would be horribly slow
#% loop-based solution:
Elapsed time is 18.105728 seconds.
#% bsxfun-based solution:
Elapsed time is 98.699396 seconds.

bsxfun は、ベクトルを行列に展開し、それを sum で折りたたみます。非常に大きなベクトルでは、これはループに比べて不必要にメモリが重いため、最終的には失われます。それ以前に、それは非常にうまくいきます。


元の遅い答え:

ここにワンライナーがあります:

out=cell2mat(arrayfun(@(x) repmat(((x>0)*2)-1+(x==0),max(1,abs(x)),1),Vec,'uni',0));
out' =

     0   1   1   1  -1  -1  -1  -1   0   0   1   1   1  -1

どうしたの:

((x>0)*2)-1 + (x==0) #% if an integer is >0, make it a 1, <0 becomes -1, 0 stays 0 

max(1,abs(x)) #% figure out how many times to replicate the value  

arrayfun(@(x) (the above stuff), Vec, 'uni', 0) #% apply the function  
 #% to each element in the array, generating a cell array output

cell2mat( (the above stuff) ) #% convert back to a matrix 
于 2012-10-27T04:18:47.527 に答える