1 function resu = cat(dim, A, varargin)
2 %# function resu = cat(dim, A, varargin)
3 %# This is the concatenation operator for a dataframe object. "Dim"
4 %# has the same meaning as ordinary cat. Next arguments may be
5 %# dataframe, vector/matrix, or two elements cells. First one is taken
6 %# as row/column name, second as data.
8 %% Copyright (C) 2009-2012 Pascal Dupuis <Pascal.Dupuis@uclouvain.be>
10 %% This file is part of Octave.
12 %% Octave is free software; you can redistribute it and/or
13 %% modify it under the terms of the GNU General Public
14 %% License as published by the Free Software Foundation;
15 %% either version 2, or (at your option) any later version.
17 %% Octave is distributed in the hope that it will be useful,
18 %% but WITHOUT ANY WARRANTY; without even the implied
19 %% warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 %% PURPOSE. See the GNU General Public License for more
23 %% You should have received a copy of the GNU General Public
24 %% License along with Octave; see the file COPYING. If not,
25 %% write to the Free Software Foundation, 51 Franklin Street -
26 %% Fifth Floor, Boston, MA 02110-1301, USA.
29 %# $Id: cat.m 9585 2012-02-05 15:32:46Z cdemills $
32 if (!isa(A, 'dataframe')),
40 for indi = 1:length(varargin),
42 if !isa(B, 'dataframe'),
43 if iscell(B) && 2 == length(B),
44 B = dataframe(B{2}, 'rownames', B{1});
46 B = dataframe(B, 'colnames', inputname(2+indi));
49 if resu._cnt(2) != B._cnt(2),
50 error('Different number of columns in dataframes');
52 %# do not duplicate empty names
53 if !isempty(resu._name{1}) || !isempty(B._name{1}),
54 if length(resu._name{1}) < resu._cnt(1),
55 resu._name{1}(end+1:resu._cnt(1), 1) = {''};
57 if length(B._name{1}) < B._cnt(1),
58 B._name{1}(end+1:B._cnt(1), 1) = {''};
60 resu._name{1} = vertcat(resu._name{1}(:), B._name{1}(:));
61 resu._over{1} = [resu._over{1} B._over{1}];
63 resu._cnt(1) = resu._cnt(1) + B._cnt(1);
64 if size(resu._ridx, 2) < size(B._ridx, 2),
65 resu._ridx(:, end+1:size(B._ridx, 2)) = NA;
66 elseif size(resu._ridx, 2) > size(B._ridx, 2),
67 B._ridx(:, end+1:size(resu._ridx, 2)) = NA;
69 resu._ridx = [resu._ridx; B._ridx];
70 %# find data with same column names
71 dummy = A._over{2} & B._over{2};
72 indA = true(1, resu._cnt(2));
73 indB = true(1, resu._cnt(2));
74 for indj = 1:resu._cnt(2),
76 indk = strmatch(resu._name{2}(indj), B._name{2}, 'exact');
79 if ~strcmp(resu._type{indj}, B._type{indk}),
80 error("Trying to mix columns of different types");
86 resu._data{indj} = [resu._data{indj}; B._data{indk}];
87 indA(indj) = false; indB(indk) = false;
89 if any(indA) || any(indB)
90 error('Different number/names of columns in dataframe');
98 for indi = 1:length(varargin),
100 if !isa(B, 'dataframe'),
101 if iscell(B) && 2 == length(B),
102 B = dataframe(B{2}, 'colnames', B{1});
104 B = dataframe(B, 'colnames', inputname(2+indi));
106 B._ridx = resu._ridx; %# make them compatibles
108 if resu._cnt(1) != B._cnt(1),
109 error('Different number of rows in dataframes');
111 if any(resu._ridx(:) - B._ridx(:))
112 error('dataframes row indexes not matched');
114 resu._name{2} = vertcat(resu._name{2}, B._name{2});
115 resu._over{2} = [resu._over{2} B._over{2}];
116 resu._data(resu._cnt(2)+(1:B._cnt(2))) = B._data;
117 resu._type(resu._cnt(2)+(1:B._cnt(2))) = B._type;
118 resu._cnt(2) = resu._cnt(2) + B._cnt(2);
124 for indi = 1:length(varargin),
126 if (!isa(B, 'dataframe')),
127 if (iscell(B) && 2 == length(B)),
128 B = dataframe(B{2}, 'rownames', B{1});
130 B = dataframe(B, 'colnames', inputname(indi+2));
133 if (resu._cnt(1) != B._cnt(1)),
134 error('Different number of rows in dataframes');
136 if (resu._cnt(2) != B._cnt(2)),
137 error('Different number of columns in dataframes');
139 %# to be merged against 3rd dim, rownames must be equals, if
140 %# non-empty. Columns are merged based upon their name; columns
141 %# with identic content are kept.
143 if size(resu._ridx, 2) < size(B._ridx, 2),
144 resu._ridx(:, end+1:size(B._ridx, 2)) = NA;
145 elseif size(resu._ridx, 2) > size(B._ridx, 2),
146 B._ridx(:, end+1:size(resu._ridx, 2)) = NA;
148 resu._ridx = cat(3, resu._ridx, B._ridx);
149 %# find data with same column names
150 indA = true(1, resu._cnt(2));
151 indB = true(1, resu._cnt(2));
152 dummy = A._over{2} & B._over{2};
153 for indj = 1:resu._cnt(2),
155 indk = strmatch(resu._name{2}(indj), B._name{2}, 'exact');
158 if (~strcmp(resu._type{indj}, B._type{indk})),
159 error("Trying to mix columns of different types");
165 if (all([isnumeric(resu._data{indj}) isnumeric(B._data{indk})])),
166 %# iterate over the columns of resu and B
167 op1 = resu._data{indj}; op2 = B._data{indk};
168 for ind2=1:columns(op2),
170 for ind1=1:columns(op1),
171 if (all(abs(op1(:, ind1) - op2(:, ind2)) <= eps)),
172 resu._rep{indj} = [resu._rep{indj} ind1];
178 %# pad in the second dim
179 resu._data{indj} = [resu._data{indj}, B._data{indk}];
180 resu._rep{indj} = [resu._rep{indj} 1+length(resu._rep{indj})];
184 resu._data{indj} = [resu._data{indj} B._data{indk}];
185 resu._rep{indj} = [resu._rep{indj} 1+length(resu._rep({indj}))];
187 indA(indj) = false; indB(indk) = false;
189 if (any(indA) || any(indB)),
190 error('Different number/names of columns in dataframe');
194 resu = df_thirddim(resu);
197 error('Incorrect call to cat');
200 %# disp('End of cat'); keyboard