diff --git a/CHANGELOG.md b/CHANGELOG.md index 98d2a10feb..84391e3167 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `end` magic keyword can be overloaded for classes (applied to `table` class). - [#1250](http://github.com/nelson-lang/nelson/issues/1250) `head`, `tail` functions for table and array. +- [#1248](http://github.com/nelson-lang/nelson/issues/1248) `removevars`, `renamevars` functions for table. ### Changed diff --git a/modules/table/functions/@table/subsasgn.m b/modules/table/functions/@table/subsasgn.m index c9b644e5c0..2c8952c7aa 100644 --- a/modules/table/functions/@table/subsasgn.m +++ b/modules/table/functions/@table/subsasgn.m @@ -56,11 +56,19 @@ if ~isequal(size(before.RowNames), size(value.RowNames)) error(_('Value assignment must be same size as existing value.')); end - if isstring(value.VariableNames) - value.VariableNames = cellstr(value.VariableNames); - end - if isstring(value.RowNames) - value.RowNames = cellstr(value.RowNames); + ce = {}; + if isstring(value.VariableNames) || iscellstr(value.VariableNames) + if iscellstr(value.VariableNames) + ce = value.VariableNames; + else + ce = cellstr(value.VariableNames); + end + R = renamevars(T, before.VariableNames, ce); + return + else + if isstring(value.RowNames) + value.RowNames = cellstr(value.RowNames); + end end st.Properties = value; R = class(st, 'table'); @@ -205,7 +213,7 @@ end else % Delete specific columns - if ~isequal(idxRow, 1:width(T)) || isempty(idxCol) + if ~isequal(idxRow, 1:height(T)) || isempty(idxCol) error(_('At least one subscript must be '':'' when you delete rows or variables by assigning [].')); end for j = idxCol diff --git a/modules/table/functions/@table/subsref.m b/modules/table/functions/@table/subsref.m index f1cea4de4f..f189612546 100644 --- a/modules/table/functions/@table/subsref.m +++ b/modules/table/functions/@table/subsref.m @@ -136,6 +136,9 @@ % Keep as is elseif ischar(rowIdx) || iscellstr(rowIdx) || isstring(rowIdx) % Handle row names + if ischar(rowIdx) + rowIdx = {rowIdx}; + end rowIdx = find(ismember(st.Properties.RowNames, rowIdx)); if isempty(rowIdx) error(_('Row name not found.')); @@ -147,6 +150,8 @@ % Handle column indexing if ischar(colIdx) && strcmp(colIdx, ':') colIdx = 1:width(T); + elseif ischar(colIdx) && isrow(colIdx) + colIdx = find(ismember(st.Properties.VariableNames, {colIdx})); elseif islogical(colIdx) colIdx = find(colIdx); elseif isnumeric(colIdx) @@ -156,6 +161,7 @@ else error(_('Invalid column indexing.')); end + selectedVarNames = st.Properties.VariableNames(colIdx); tableData = cell(1, length(selectedVarNames)); for i = 1:length(selectedVarNames) diff --git a/modules/table/functions/removevars.m b/modules/table/functions/removevars.m new file mode 100644 index 0000000000..b33b156fad --- /dev/null +++ b/modules/table/functions/removevars.m @@ -0,0 +1,23 @@ +%============================================================================= +% Copyright (c) 2016-present Allan CORNET (Nelson) +%============================================================================= +% This file is part of the Nelson. +%============================================================================= +% LICENCE_BLOCK_BEGIN +% SPDX-License-Identifier: LGPL-3.0-or-later +% LICENCE_BLOCK_END +%============================================================================= +function varargout = removevars(varargin) + nargoutchk(0, 1); + narginchk(1, 2); + T = varargin{1}; + mustBeA(T, 'table', 1); + if (nargin < 2) + vars = []; + else + vars = varargin{2}; + end + T(:, vars) = []; + varargout{1} = T; +end +%============================================================================= diff --git a/modules/table/functions/renamevars.m b/modules/table/functions/renamevars.m new file mode 100644 index 0000000000..1fe225666a --- /dev/null +++ b/modules/table/functions/renamevars.m @@ -0,0 +1,88 @@ +%============================================================================= +% Copyright (c) 2016-present Allan CORNET (Nelson) +%============================================================================= +% This file is part of the Nelson. +%============================================================================= +% LICENCE_BLOCK_BEGIN +% SPDX-License-Identifier: LGPL-3.0-or-later +% LICENCE_BLOCK_END +%============================================================================= +function varargout = renamevars(varargin) + narginchk(3, 3); % Check that there are exactly 3 input arguments + nargoutchk(0, 1); % Check that there is at most 1 output argument + + % Unpack input arguments + T = varargin{1}; + oldNames = varargin{2}; + newNames = varargin{3}; + + % Ensure the types are correct + mustBeA(T, 'table', 1); % Check if T is a table + mustBeText(oldNames, 2); % Check if oldNames are text + mustBeText(newNames, 3); % Check if newNames are text + + % Convert oldNames and newNames to cell arrays of strings + oldNames = cellstr(oldNames); + newNames = cellstr(newNames); + + % Ensure oldNames and newNames are the same length + if (length(oldNames) ~= length(newNames)) + error(_('oldNames and newNames must have the same length.')); + end + + % Check for duplicates in oldNames + if (length(unique(oldNames)) ~= length(oldNames)) + error('Duplicate names in oldNames are not allowed.'); + end + + % Check for duplicates in newNames + if (length(unique(newNames)) ~= length(newNames)) + error('Duplicate names in newNames are not allowed.'); + end + + % Convert table to struct + st = struct(T); + + % Get current fieldnames from st.data + currentFields = fieldnames(st.data); + + % Check if all oldNames exist in the current fieldnames + for i = 1:length(oldNames) + if ~any(strcmp(oldNames{i}, currentFields)) + error(sprintf(_('Name "%s" not found in the table.'), oldNames{i})); + end + end + + % Create new struct for renamed fields + newData = struct(); + + % Copy and rename fields + for i = 1:length(currentFields) + currentField = currentFields{i}; + idx = find(strcmp(currentField, oldNames)); + + if ~isempty(idx) + % If field should be renamed, use new name + newData.(newNames{idx}) = st.data.(currentField); + else + % If field is not in oldNames, keep original name + newData.(currentField) = st.data.(currentField); + end + end + + % Replace old data struct with new one + st.data = newData; + + % Update VariableNames in Properties + oldVarNames = st.Properties.VariableNames; + newVarNames = oldVarNames; + for i = 1:length(oldNames) + idx = strcmp(oldNames{i}, oldVarNames); + if any(idx) + newVarNames{idx} = newNames{i}; + end + end + st.Properties.VariableNames = newVarNames; + + varargout{1} = class(st, 'table'); +end diff --git a/modules/table/help/en_US/xml/removevars.xml b/modules/table/help/en_US/xml/removevars.xml new file mode 100644 index 0000000000..eb3f3c7923 --- /dev/null +++ b/modules/table/help/en_US/xml/removevars.xml @@ -0,0 +1,82 @@ + + + SAME AS NELSON SOFTWARE + + en_US + removevars + Delete variables from table. + + + TB = removevars(TA, varsNames) + + + + + + TA + Input table. + + + varsNames + Variable names in input table to remove: character vector, string array or cell array of character vectors. + + + + + + + TB + Table object modified. + + + + +

TB = removevars(TA, varsNames) removes the variables specified by varsNames from the table TA and stores the remaining variables in T2.

+

You can specify the variables by name, position, or using logical indices.

+

You can also remove variables from a table using T(:, varsNames) = [].

+
+ + + + + + + nelson + + + + + + + + + + table + + + renamevars + + + + + + + 1.9.0 + initial version + + + + + Allan CORNET + +
diff --git a/modules/table/help/en_US/xml/renamevars.xml b/modules/table/help/en_US/xml/renamevars.xml new file mode 100644 index 0000000000..f3989cac49 --- /dev/null +++ b/modules/table/help/en_US/xml/renamevars.xml @@ -0,0 +1,94 @@ + + + SAME AS NELSON SOFTWARE + + en_US + renamevars + Rename variables in table. + + + TB = renamevars(TA, varsNames, newNames) + + + + + + TA + Input table. + + + varsNames + Variable names in input table: character vector, string array or cell array of character vectors. + + + newNames + New names for variables: character vector, string array or cell array of character vectors. + + + + + + + TB + Table object with variable names modified. + + + + +

TB = renamevars(TA, varsNames, newNames) renames the variables in the table TA as specified by varsNames and assigns them the new names provided in newNames.

+

You can also rename all the variables in a table by assigning new names to its VariableNames property using T.Properties.VariableNames = newNames.

+

In this case, newNames must be a string array or a cell array of character vectors.

+
+ + + + + + + nelson + + + + + + + + + + table + + + removevars + + + + + + + 1.9.0 + initial version + + + + + Allan CORNET + +
diff --git a/modules/table/tests/test_removars.m b/modules/table/tests/test_removars.m new file mode 100644 index 0000000000..70bc62034e --- /dev/null +++ b/modules/table/tests/test_removars.m @@ -0,0 +1,27 @@ +%============================================================================= +% Copyright (c) 2016-present Allan CORNET (Nelson) +%============================================================================= +% This file is part of the Nelson. +%============================================================================= +% LICENCE_BLOCK_BEGIN +% SPDX-License-Identifier: LGPL-3.0-or-later +% LICENCE_BLOCK_END +%============================================================================= +LastName = {'Sanchez';'Johnson';'Li';'Diaz';'Brown'}; +Age = [38;43;38;40;49]; +Smoker = logical([1;0;1;0;1]); +Height = [71;69;64;67;64]; +Weight = [176;163;131;133;119]; +BloodPressure = [124 93; 109 77; 125 83; 117 75; 122 80]; +T = table(LastName, Age, Smoker, Height, Weight, BloodPressure); +R = removevars(T, 'Age'); +REF = table(LastName, Smoker, Height, Weight, BloodPressure); +assert_isequal(R, REF); +R2 = removevars(R, 1); +REF = table(Smoker, Height, Weight, BloodPressure); +assert_isequal(R2, REF); +%============================================================================= +R = removevars(T,{'Smoker','Weight'}); +REF = table(LastName, Age, Height, BloodPressure); +assert_isequal(R, REF); +%============================================================================= diff --git a/modules/table/tests/test_renamevars.m b/modules/table/tests/test_renamevars.m new file mode 100644 index 0000000000..68bb233ba3 --- /dev/null +++ b/modules/table/tests/test_renamevars.m @@ -0,0 +1,33 @@ +%============================================================================= +% Copyright (c) 2016-present Allan CORNET (Nelson) +%============================================================================= +% This file is part of the Nelson. +%============================================================================= +% LICENCE_BLOCK_BEGIN +% SPDX-License-Identifier: LGPL-3.0-or-later +% LICENCE_BLOCK_END +%============================================================================= +LastName = {'Sanchez';'Johnson';'Li';'Diaz';'Brown'}; +Age = [38;43;38;40;49]; +Smoker = logical([1;0;1;0;1]); +Height = [71;69;64;67;64]; +Weight = [176;163;131;133;119]; +BloodPressure = [124 93; 109 77; 125 83; 117 75; 122 80]; +T = table(LastName, Age, Smoker, Height, Weight, BloodPressure); +T2 = table(LastName, Age, Smoker, Height, Weight, BloodPressure); +R = renamevars(T, 'LastName', 'Name'); +REF = table(LastName, Age, Smoker, Height, Weight, BloodPressure, 'VariableNames', {'Name', 'Age', 'Smoker', 'Height', 'Weight', 'BloodPressure'}); +assert_isequal(R, REF); +assert_isequal(T, T2); +%============================================================================= +LastName = {'Sanchez';'Johnson';'Li';'Diaz';'Brown'}; +Age = [38;43;38;40;49]; +Smoker = logical([1;0;1;0;1]); +Height = [71;69;64;67;64]; +Weight = [176;163;131;133;119]; +BloodPressure = [124 93; 109 77; 125 83; 117 75; 122 80]; +T = table(LastName, Age, Smoker, Height, Weight, BloodPressure) +T.Properties.VariableNames = {'N1', 'A2', 'S3', 'H4', 'W5', 'B6'}; +T_REF = table(LastName, Age, Smoker, Height, Weight, BloodPressure, 'VariableNames', {'N1', 'A2', 'S3', 'H4', 'W5', 'B6'}); +assert_isequal(T, T_REF); +%=============================================================================