У меня есть две матрицы 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
Вот решение без использования цикла. Тем не менее, я не совсем уверен, что это будет быстрее, чем цикл.
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'),:)];