Reputation: 13
I have two arrays, A
and B
. The first digit of each row is the serial number.
How do I combine A
and B
to have an array C
, such that all rows in A
with the same serial number in B
are concatenated horizontally?
A = [ 12345;
47542;
32673;
65436;
75343;
23496;
54765 ]
B = [ 23566;
33425;
65438;
75354 ]
y = ismember(A(:,1), B(:,1), 'rows');
t=find(y);
C= [A(t,1:12),B(t,1:12)];
I need C
to be:
C = [ 12345, 00000;
23496, 23566;
32673, 33425;
47542, 00000;
54765, 00000;
65436, 00000;
75343, 75354]
Upvotes: 0
Views: 76
Reputation: 30046
If it's only the first digit, we only need to check if the first digit (i.e. floor(A/1e4)
) matches 0
to 9
, and index accordingly...
% Add some zeros at the front to make indexing work with the unmatched ismember outputs
Az = [zero(; A]; Bz = [0; B];
% Find the indices for 0 to 9 within the first digits of A and B
[~,ia] = ismember( 0:9, floor( A/1e4 ) );
[~,ib] = ismember( 0:9, floor( B/1e4 ) );
% Assign to C and discard unmatched rows
C = [Az(ia+1), Bz(ib+1)];
C( all( C==0, 2 ), : ) = [];
Note that keeping things numeric with the floor
operation should always be preferable to flipping between numeric and character data with things like num2str
...
Edit
You changed the scope of the question by commenting with new data. Here is the same method, written to be more generic so it handles A
and B
with more columns and different magnitude IDs
% Add some zeros at the front to make indexing work with the unmatched ismember outputs
Az = [zeros(1,size(A,2)); A]; Bz = [zeros(1,size(A,2)); B];
% Function for getting first digit
f = @(x) floor(x./(10.^floor(log10(x))));
% Find the indices for 0 to 9 within the first digits of A and B
[~,ia] = ismember( 0:9, f(A(:,1)) );
[~,ib] = ismember( 0:9, f(B(:,1)) );
% Assign to C and discard unmatched rows
C = [Az(ia+1,:), Bz(ib+1,:)];
C( all( C==0, 2 ), : ) = [];
Upvotes: 1
Reputation: 18905
First of all, the whole script. At first glance, I couldn't find a solution without using loops.
A = [ 12345;
47542;
32673;
65436;
75343;
23496;
54765; ]
B = [ 23566;
33425;
65438;
75354; ]
A = sort(A); % Sort A and B.
B = sort(B);
A_str = int2str(A); % Convert integers to chars.
B_str = int2str(B);
A_sn = A_str(:, 1); % Extract first columns.
B_sn = B_str(:, 1); % Basically, these are the serial numbers.
C = zeros(size(A, 1), size(A, 2) * 2); % Initialize C.
C(:, 1) = A; % First column of C is just A.
for i = 1:length(A_sn) % For all serial numbers in A...
for j = 1:length(B_sn) % For all serial numbers in B...
if (A_sn(i) == B_sn(j)) % Check if serial number in B equals the serial number in A.
C(i, 2) = B(j); % If so, set i-th row in C to the corresponding value in B.
end
end
end
C
Results in:
A =
12345
47542
32673
65436
75343
23496
54765
B =
23566
33425
65438
75354
C =
12345 0
23496 23566
32673 33425
47542 0
54765 0
65436 65438
75343 75354
Upvotes: 0
Reputation: 899
My approach would be the following, extract the leading digits of both arrays and compare those:
a=num2str(A)-'0';
b=num2str(B)-'0';
[ida,idb]=ismember(a(:,1),b(:,1));
Now get the sorting index of A
[~,ids]=sort(a(:,1));
Create output array
C=zeros(size(A,1),2);
Finally assign and sort output
C(:,1)=A;
C(ida,2)=B(idb(idb>0));
%sort result
C=C(ids,:)
Upvotes: 2