2012-12-30 16 views
8
map1 = containers.Map({'212','2','12','44'},[4,5,6,7]); 
keyset = str2double(keys(map1)); 

Teraz robię zestaw operacji na Keyset który oddaMatlab: Konwersja podwójną tablicę wektor do macierzy komórkowej strun

Keyset= [203,2,12,39]; 

Próbowałam następujące:

num2cell(num2str(keyset)); 
num2cell(num2str(keyset,1)); 
num2cell(num2str(keyset,'%11.0g')); 
num2cell(num2str(keyset,3)); 

wszystkie powyższe dały dziwne wyniki w końcowej macierzy komórek. Potrzebuję tylko liczb całkowitych do użycia jako klucze do innej mapy kontenera.

+2

Więc jaki jest pożądany rezultat? Czy to jest '{'203', '2', '12', '39'}'? –

Odpowiedz

13

I zaproponowanie 5 dodatkowych rozwiązań, z których trzy są 4-5x szybciej niż dotychczas proponowane rozwiązania. Wnioski wyciągnięte z tego są:

  • num2str jest powolny
  • cellfun i arrayfun można dodać poważnych trudności
  • Istnieje wiele sposobów, aby przekonwertować tablicę numeryczną do macierzy komórkowej strun.

trzech roztworów najwyższej wydajności są bardzo podobne pod względem osiągów:

zapętlenie przypisanie elementów komórkowych

n4 = length(Keyset); 
tmp4 = cell(n4,1); 
for i4 = 1:n4 
    tmp4{i4} = sprintf('%i',Keyset(i4)); 
end 

konwersji wszystkich ciąg i wywołanie textscan

tmp6 = textscan(sprintf('%i\n',Keyset'),'%s'); 
tmp6 = tmp6{1}; 

Konwertowanie wszystkich na ciągi i wywoływanie regexp.

tmp3 = regexp(sprintf('%i ',Keyset),'(\d+)','match'); 

Oto pełny kod testu z synchronizacją:

function t = speedTest 

t=zeros(7,1); 
for ii=1:100, 
    Keyset=randi(1,10,100); % random keys 
    tic; 
    eval([ 'tmp1 = { ', sprintf(' %d ', Keyset), ' }; ']); 
    t(1)=t(1)+toc; 
    tic; 
    tmp2=arrayfun(@num2str, Keyset, 'Uniform', false); 
    t(2)=t(2)+toc; 

    tic; 
    tmp3 = regexp(sprintf('%i ',Keyset),'(\d+)','match'); 
    t(3) = t(3)+toc; 

    tic; 
    n4 = length(Keyset); 
    tmp4 = cell(n4,1); 
    for i4 = 1:n4 
     tmp4{i4} = sprintf('%i',Keyset(i4)); 
    end 
    t(4) = t(4)+toc; 

    tic; 
    n5 = length(Keyset); 
    tmp5 = cell(n5,1); 
    for i5 = 1:n5 
     tmp4{i5} = num2str(Keyset(i5)); 
    end 
    t(5) = t(5)+toc; 

    tic; 
    tmp6 = textscan(sprintf('%i\n',Keyset'),'%s'); 
    tmp6 = tmp6{1}; 
    t(6) = t(6)+toc; 

    tic; 
    tmp7 = num2cell(Keyset); 
    tmp7 = cellfun(@(x)sprintf('%i',x),tmp7,'uni',false); 
    t(7) = t(7)+toc; 


end; 
t 

t = 

    1.7820 
    21.7201 
    0.4068 
    0.3188 
    2.2695 
    0.3488 
    5.9186 
+0

+1 dla rozwiązania 'regexp' i szczegóły! – Shai

+0

Yay, mój jest najwolniejszy! Ale jak skończyliśmy rozmawiać o występie tutaj? :-) –

+0

@EitanT: To nie byłem ja! To był Shai, który to rozpoczął. – Jonas

3

Jak o:

eval([ 'NewKeySetStr = { ', sprintf(' %d ', Keyset), ' }; ']); 
NewKeySetStr 

nie jestem pewien, że to jest najbardziej elegancki sposób, aby osiągnąć pożądane rezultaty, ale wydaje się działać ...

Porównując czas pracy za pomocą roztworu Eitan:

t=zeros(2,1); 
for ii=1:100, 
    Keyset=randi(1,10,100); % random keys 
    tic; 
    eval([ 'NewKeySetStr = { ', sprintf(' %d ', Keyset), ' }; ']); 
    t(1)=t(1)+toc; 
    tic; 
    tmp=arrayfun(@num2str, Keyset, 'Uniform', false); 
    t(2)=t(2)+toc; 
end; 
t 

Plony:

t = 
    0.3986 
    2.2527 

Wygląda na to, że proponowane rozwiązanie jest szybsze.

Uwaga: wygląda na to, że obecna implementacja cellfun nie jest zoptymalizowana pod kątem prędkości. Mówi się, że w przyszłych wersjach Mathworks zamierza wprowadzić lepszą implementację cellfun. Tak więc rozwiązanie Eitana może nie być optymalne w obecnej wersji, ale wydaje się, że jest to dobra praktyka umiejętności Matlaba.

+0

+1: Mimo że twoje rozwiązanie używa 'eval', to wciąż jest szybkie. Zastanawiam się jednak, czy działa na bardzo duże tablice. Przy okazji, uważam, że '0.3s' różni się od' 2.2s' o ok. jeden rząd lub wielkość (nie dwie). –

+0

@EitanT - oops. poprawione. – Shai

+0

Bardzo trudno nie dać ci -1 za rozwiązanie "zła". Na szczęście istnieją co najmniej 3 rozwiązania, które są szybsze. – Jonas

7

Jak o:

arrayfun(@num2str, Keyset, 'Uniform', false)' 

który powinien dawać tablicy 4-1 przez komórki dla przykładu:

ans = 
    '203' 
    '2' 
    '12' 
    '39' 
+0

Proszę zobaczyć moją zredagowaną odpowiedź. Dzięki. – Shai

+0

@Shai nie jest pewien, czy OP szuka w tym przypadku wydajności. –

+0

dlatego dodałem "notatkę" na dole - twoje rozwiązanie jest bardziej "Matlabowe" niż moje, ale przy niewielkim koszcie wykonywania ... – Shai

0

zorientowali się, jak poprawić rozwiązanie dla dużych liczb całkowitych regexp, wykorzystując funkcję podziału. Również zostałem wprowadzony w błąd przez jedno z rozwiązań Jonasa, które nie oceniało wszystkich połączeń sprintf w pętli for. Edycja: dodano także nową funkcję sznurka 2016 sugerowaną w komentarzach.

t = speedTest() 

function t = speedTest 

t=zeros(5,1); 
for ii=1:100 
    Keyset=randi(10000000,10,1000); % random keys 

    tic; 
    n4 = numel(Keyset); % changed to numel (length only gives number of columns) 
    tmp1 = cell(n4,1); 
    for i4 = 1:n4 
     tmp1{i4} = sprintf('%i',Keyset(i4)); 
    end 
    t(1) = t(1)+toc; 

    tic; 
    tmp2 = regexp(sprintf('%i ',Keyset),'(\d+)','match'); 
    t(2) = t(2)+toc; 

    tic; 
    tmp3 = regexp(sprintf('%i ',Keyset),' ','split'); 
    tmp3(end) = []; 
    t(3) = t(3)+toc; 

    tic; 
    tmp4 = string(Keyset(:)); 
    t(4) = t(4)+toc; 

    # test in case you want to go back to characters 
    tic; 
    tmp5 = char(string(Keyset(:))); 
    t(5) = t(5)+toc; 
end 
end 

Rozwiązanie regexp z rentowności podzielone nieco lepszej wydajności i metody strun jest jeszcze szybsze:

t = 

    6.1916 
    1.1292 
    0.8962 
    0.6671 
    0.7523 
+0

Począwszy od 16b MATLAB ma typ danych łańcuchowych. string (Keyset) jest ~ 25% szybszy niż twój najszybszy przypadek. – matlabbit

+1

Mój początkowy eksperyment polegał na użyciu tmp4 = string (Keyset), który powoduje zniszczenie istniejącego tmp4. Podczas korzystania z nowej zmiennej ciąg (Keyset) jest o 40% szybszy niż Twój najszybszy przypadek. – matlabbit

Powiązane problemy