2012-01-18 4 views
1

У меня есть матрица, как следующие (произвольные Cols/строки):Matlab: Поиск строк в матрице с фиксированным первым и последним элементом с векторизацией

1 0 0 0 0 
1 2 0 0 0 
1 2 3 0 0 
1 2 3 4 0 
1 2 3 4 5 
1 2 5 0 0 
1 2 5 3 0 
1 2 5 3 4 
1 4 0 0 0 
1 4 2 0 0 
1 4 2 3 0 
1 4 2 5 0 
1 4 2 5 3 
1 4 5 0 0 
1 4 5 3 0 
2 0 0 0 0 
2 3 0 0 0 
2 3 4 0 0 
2 3 4 5 0 
2 5 0 0 0 
2 5 3 0 0 
2 5 3 4 0 
3 0 0 0 0 
3 4 0 0 0 
3 4 2 0 0 
3 4 2 5 0 
3 4 5 0 0 

и теперь я хочу, чтобы получить все строки, где первый элемент - это некоторое значение X, а последний элемент (то есть последний элемент! = 0) - это определенное значение Y, OR повернуто: первое - это Y, а последнее - X.

Невозможно увидеть скорый код который НЕ использует for-loop :( Спасибо!

EDIT: Для фильтрации всех строк с определенным первым элементом очень просто, вам не нужно помогать мне здесь. Итак, давайте предположим, я только хочу сделать следующее: Фильтр все строки, в которых последний элемент (т.е. последний элемент = 0 в каждой строке!) Либо X или Y.

EDIT Спасибо большое за ваши посты , Я сравнил три возможных решения с матрицей из 473408 * 10 элементов. Вот benchmarkscript: http://pastebin.com/9hEAWw9a

Результаты были:

t1 = 2.9425 Jonas 
t2 = 0.0999 Brendan 
t3 = 0.0951 Oli 

Так Большое спасибо вам, ребята, я придерживаюсь раствором Oli и, таким образом, принять его. Спасибо, хотя для всех других решений!

ответ

2

Вот трюк: Посмотрите для чисел с 0 справа, и суммировать их все:

H=[1 2 0 0 0; 
    2 3 1 0 0; 
    4 5 8 0 0; 
    8 5 4 2 2]; 

lastNumber=sum(H.*[H(:,2:end)==0 true(size(H,1),1)],2) 

ans = 

    2 
    1 
    8 
    2 

остальное просто:

firstNumber=H(:,1); 

find((firstNumber==f) & (lastNumber==l)) 
+0

хорошая идея, даже если она потерпит неудачу, если есть нули до конца. +1 в любом случае – Jonas

+0

@Jonas: Вы имеете в виду, как в решении brendan? На самом деле, как я прокомментировал пост brendans, это не имеет значения, поскольку на самом деле есть ТОЛЬКО нули в конце. – tim

+0

@ Oli: Спасибо Оли, это тоже очень приятно! Посмотрите на мое редактирование в первом посте, есть тестовый скрипт, и ваш скрипт побеждает (: Таким образом, я принял! – tim

5

Все, что вам нужно сделать, это найти линейные индексы последнего ненулевого элемента каждой строки. Остальное просто:

[nRows,nCols] = size(A); 
[u,v] = find(A); %# find all non-zero elements in A 
%# for each row, find the highest column index with accumarray 
%# and convert to linear index with sub2ind 
lastIdx = sub2ind([nRows,nCols],(1:nRows)',accumarray(u,v,[nRows,1],@max,NaN)); 

Для фильтрации строк, то вы можете написать

goodRows = A(:,1) == X & A(lastIdx) == Y 
+0

T шляпа кажется приятной, спасибо. Я проверю это завтра и, чем расскажу! Даже не знал о 'sub2ind()', так что это бы дало мне много головной боли :) Но если кто-нибудь это знает, это может быть легко, ха-ха. Спасибо, пока! Редактировать: И также не знал 'accumarray' :) – tim

+0

@ColHeather: accumarray - это функция, которая вначале немного сложна для понимания, но это невероятно полезно. – Jonas

+1

Это работает даже в том случае, если у моего решения нет. Нужно будет читать «accarray» ... – Brendan

1

Это работает производится только при числе в каждой строке равны й количество не нули, за которыми следует ряд нули. то есть он не будет работать, если возможно следующее 1 0 3 4 0 0, я полагаю, что не представляется возможным на основе ввода образца вы дали ...

% 'a' is your array 
[nx, ny] = size(a); 
inds = [0:ny:ny*(nx-1)]' + sum(a ~= 0, 2); 
% Needs to transpose so that the indexing reads left-to-right 
aT = a'; 
valid1 = aT(inds) == Y; 
valid2 = a(:,1) == X; 
valid = valid1 & valid2; 
valid_rows = a(valid,:); 

Это грязный я знаю ...

+0

Да, в конце будут ТОЛЬКО нули, как и сказал :) Также попробую завтра, спасибо! – tim

+0

Хорошо, спасибо Брендану, это работает очень хорошо для меня. Посмотрите на мое редактирование выше для эталонных тестов :-) Вы очень близки к решению Оли ... :) – tim