Найти индексы строк различных значений в матрице
Имея матрицу A (n*2) в качестве источника и B в качестве вектора, содержащего подмножество элементов A, я бы хотел найти индекс строки элементов.
A=[1 2;1 3; 4 5];
B=[1 5];
F=arrayfun(@(x)(find(B(x)==A)),1:numel(B),'UniformOutput',false)
дает следующие выходные данные в ячейке согласно этой странице справки
[2x1 double] [6]
с указанием индексов всех встречаемости по столбцам. Но я бы хотел иметь индексы строк. т.е. я хотел бы знать, что элемент 1 находится в строке 1 и строке 2, а элемент 5 - только в строке 3. Если бы индексы были построчными, я мог бы использовать ceil(F{x}/2), чтобы получить желаемый результат, Теперь с переменным количеством строк, каково ваше предлагаемое решение? Может случиться так, что в функции ismember нет полного тега включения 'rows'. Кроме того, я хотел бы знать все показатели указанных элементов. Заранее благодарю за любую помощь.
3 ответа
Подход 1
Преобразовать F
из текущей формы линейного индекса в индексы строк используйте mod
:
rows = cellfun(@(x) mod(x-1,size(A,1))+1, F, 'UniformOutput', false);
Вы можете объединить это с вашим кодом в одну строку. Обратите внимание, что вы можете напрямую использовать B
в качестве входа в arrayfun
и вы избегаете одного этапа индексации:
rows = arrayfun(@(x) mod(find(x==A)-1,size(A,1))+1, B(:), 'UniformOutput', false);
Как это работает:
F
как дано вашим кодом является линейным индексом в форме столбца. Это означает, что индекс работает по первому столбцу B
, начало начинается в верхней части второго столбца и снова уменьшается, и т. д. Таким образом, номер строки можно получить только по модулю (mod
) операция.
Подход 2
С помощью bsxfun
а также accumarray
:
t = any(bsxfun(@eq, B(:), reshape(A, 1, size(A,1), size(A,2))), 3); %// occurrence pattern
[ii, jj] = find(t); %// ii indicates an element of B, and jj is row of A where it occurs
rows = accumarray(ii, jj, [], @(x) {x}); %// group results according to ii
Как это работает:
Если предположить, A
а также B
как в вашем примере, t
это матрица 2x3
t =
1 1 0
0 0 1
М-й ряд t
содержит 1
в столбце n, если m-й элемент B
происходит в n-м ряду B
, Эти значения преобразуются в форму строки и столбца с find
:
ii =
1
1
2
jj =
1
2
3
Это означает, что первый элемент B
в рядах 1 и 2 A
; а второй происходит в строке 3 B
,
Наконец, значения jj
сгруппированы (с accumarray
в соответствии с их соответствующей стоимостью ii
генерировать желаемый результат.
Один подход с bsxfun
& accumarray
-
%// Create a match of B's in A's with each column of matches representing the
%// rows in A where there is at least one match for each element in B
matches = squeeze(any(bsxfun(@eq,A,permute(B(:),[3 2 1])),2))
%// Get the indices values and the corresponding IDs of B
[indices,B_id] = find(matches)
%// Or directly for performance:
%// [indices,B_id] = find(any(bsxfun(@eq,A,permute(B(:),[3 2 1])),2))
%// Accumulate the indices values using B_id as subscripts
out = accumarray(B_id(:),indices(:),[],@(x) {x})
Пробный прогон -
>> A
A =
1 2
1 3
4 5
>> B
B =
1 5
>> celldisp(out) %// To display the output, out
out{1} =
1
2
out{2} =
3
С arrayfun
, ismember
а также find
[r,c] = arrayfun(@(x) find(ismember(A,x)) , B, 'uni',0);
куда r
дает желаемые результаты, вы также можете использовать c
переменная, чтобы получить столбец каждого числа в B
Результаты для ввода образца:
>> celldisp(r)
r{1} =
1
2
r{2} =
3
>> celldisp(c)
c{1} =
1
1
c{2} =
2