Вопрос:
У меня есть две матрицы A и B в Matlab. A имеет размерность mx6, например
A=[ 1 1 1 1 | 1 0; 1 1 1 2 | 1 0; 1 1 1 3 | 1 0; 1 1 1 4 | 1 0; 1 2 3 2 | 1 0; 1 2 3 3 | 1 0; 1 2 3 4 | 1 0]
B имеет размерность nx6, например
B=[ 1 1 1 1 | 1 1; 1 2 3 1 | 1 1]
Я хочу объединить A и B и создать матрицу C после этих шагов без использования циклов:
1) Рассмотрим B(i,1:4); если существует j такое, что A(j,1:4) равно B(i,1:4) [это может произойти не более одного j], а затем C(i,:)=[B(i,1:4) A(j,5)+B(i,5) A(j,6)+B(i,6)]. Сделайте это для всех i=1,…,n.
2) Заполните оставшиеся строки C строками A и B, которые не могут быть сопоставлены в соответствии с шагом 1).
В примере
C=[ 1 1 1 1 | 2 1; %Step 1) above ———————————— 1 1 1 2 | 1 0; %Step 2) above 1 1 1 3 | 1 0; %firstly rows from A 1 1 1 4 | 1 0; 1 2 3 2 | 1 0; 1 2 3 3 | 1 0; 1 2 3 4 | 1 0; 1 2 3 1 | 1 1] %lastly rows from B
Моя попытка с использованием циклов:
%STEP 1 for i=1:size(B,1) for j=1:size(A,1) if all(B(i,1:4)==A(j,1:4),2) C(i,:)=[B(i,1:4) A(j,5)+B(i,5) A(j,6)+B(i,6)] end end end %STEP 2 C=[ C; A(logical(1-ismember(A(:,1:4), B(:,1:4),’rows’)),:)]; C=[ C; B(logical(1-ismember(B(:,1:4), A(:,1:4),’rows’)),:)]; Лучший ответ:
Это довольно легко, используя комбинацию unique и accumarray. unique работает, предоставляя вам матрицу вывода, в которой удаляются все повторяющиеся записи. Это будет хорошо работать, когда речь идет о играх с A и B.
Просто объедините A и B вместе в единую консолидированную матрицу, затем используйте unique с первыми четырьмя столбцами и назначьте каждой строке этой усеченной матрицы уникальный идентификатор. Третий вывод unique даст вам этот идентификатор, и если вы хотите узнать, какой идентификатор соответствует той строке, которая выводится из первого вывода unique, где каждая строка вывода дает вам идентификатор, который соответствует к.
Вы должны использовать флаг ‘rows’ и ‘stable’, чтобы убедиться, что мы смотрим на каждую строку, а не на каждый отдельный элемент в матрице и с флагом ‘stable’, мы присваиваем идентификаторы на основе того, когда мы сталкиваемся с уникальным начиная с начала (сверху) до финиша (снизу). Если вы не поместили флаг ‘stable’, он бы сортировал строки внутри, а затем присваивал идентификаторы, начиная с верхней части этого списка.
Если вы хотите достичь желаемого результата, вы должны использовать ‘stable’. Когда вы найдете эти идентификаторы, используйте accumarray дважды на пятом и шестом столбцах соответственно и примените отдельную сумму и объедините результаты вместе. accumarray работает, предоставляя набор идентификаторов или ключей, а для каждого ID/ключа – выходное значение, связанное с этим ключом. Вы группируете все значения, которые используют один и тот же ключ, и делайте что-то для каждой группы. В нашем случае мы будем применять accumarray дважды, где первый набор выходных значений поступает из пятого столбца, а второй набор выходных значений – из шестого столбца. Поведение по умолчанию с accumarray равно sum всем значениям, принадлежащим одной и той же группе, которые вы хотели.
Вывод accumarray в нашем случае будет единственным вектором столбца, до тех пор, пока общее число уникальных идентификаторов, сгенерированных на первом этапе, с unique. Вы делаете это для пятого и шестого столбцов отдельно, затем для получения окончательной матрицы просто объедините первый вывод unique, а также два выхода accumarray в одну матрицу, чтобы, наконец, получить выход.
Что-то вроде этого:
%// Your data A=[ 1 1 1 1 1 0; 1 1 1 2 1 0; 1 1 1 3 1 0; 1 1 1 4 1 0; 1 2 3 2 1 0; 1 2 3 3 1 0; 1 2 3 4 1 0]; B=[ 1 1 1 1 1 1; 1 2 3 1 1 1]; %// Solution [cols,~,id] = unique([A(:,1:4); B(:,1:4)], ‘rows’, ‘stable’); out = accumarray(id, [A(:,5); B(:,5)]); out2 = accumarray(id, [A(:,6); B(:,6)]); final = [cols out out2];
Это наш вывод:
final = 1 1 1 1 2 1 1 1 1 2 1 0 1 1 1 3 1 0 1 1 1 4 1 0 1 2 3 2 1 0 1 2 3 3 1 0 1 2 3 4 1 0 1 2 3 1 1 1 Ответ №1
Вот решение без использования цикла. Тем не менее, я не совсем уверен, что это будет быстрее, чем цикл.
ind = 1:size(B,1); [indA, indA_true] = ismember(A(:,1:4),B(:,1:4),’rows’); indB = indA_true(find(indA_true)); C = [A(indA,1:4), A(indA,5:6) + B((indB),5:6)]; C = [C; A(~indA,:); B(~ismember(ind’,indB,’rows’),:)];