Skip to content

Commit

Permalink
GH-37569: [MATLAB] Implement isequal for the arrow.type.Field MAT…
Browse files Browse the repository at this point in the history
…LAB class (#37617)

### Rationale for this change

Following on to #37474, #37446, and #37525, we should implement `isequal` for the `arrow.type.Field` MATLAB class.

### What changes are included in this PR?

1. Implemented the `isequal` method for `arrow.type.Field`

### Are these changes tested?

Yes. Add new unit tests to `tField.m`

### Are there any user-facing changes?

Yes. Users can now call `isequal` on `arrow.type.Field`s to determine if two fields are equal.

**Example**
```matlab
>> f1 = arrow.field("A", arrow.time32(TimeUnit="Second"));
>> f2 = arrow.field("B", arrow.time32(TimeUnit="Second"));
>> f3 = arrow.field("A", arrow.time32(TimeUnit="Millisecond"));

>> isequal(f1, f1)

ans =

  logical

   1

% Name properties differ
>> isequal(f1, f2)

ans =

  logical

   0

% Type properties differ
>> isequal(f1, f3)

ans =

  logical

   0
```

### Future Directions

1. #37568
2. #37570

* Closes: #37569

Authored-by: Sarah Gilmore <sgilmore@mathworks.com>
Signed-off-by: Kevin Gurney <kgurney@mathworks.com>
  • Loading branch information
sgilmore10 committed Sep 7, 2023
1 parent 5a78169 commit 3aa7e24
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 3 deletions.
45 changes: 42 additions & 3 deletions matlab/src/matlab/+arrow/+type/Field.m
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
%FIELD A class representing a name and a type.
% Fields are often used in tabular schemas for describing a column's
% name and type.

% Licensed to the Apache Software Foundation (ASF) under one or more
% contributor license agreements. See the NOTICE file distributed with
% this work for additional information regarding copyright ownership.
Expand All @@ -14,9 +18,6 @@
% permissions and limitations under the License.

classdef Field < matlab.mixin.CustomDisplay
%FIELD A class representing a name and a type.
% Fields are often used in tabular schemas for describing a column's
% name and type.

properties (GetAccess=public, SetAccess=private, Hidden)
Proxy
Expand Down Expand Up @@ -50,6 +51,44 @@
name = obj.Proxy.getName();
end

function tf = isequal(obj, varargin)
narginchk(2, inf);
tf = false;

namesToCompare = strings(numel(obj), numel(varargin));
typesToCompare = cell([1 numel(varargin)]);

for ii = 1:numel(varargin)
field = varargin{ii};
if ~isa(field, "arrow.type.Field") || ~isequal(size(obj), size(field))
% Return early if field is not an arrow.type.Field
% or if the dimensions of obj and field do not match.
return;
end

namesToCompare(:, ii) = [field(:).Name];
typesToCompare{1, ii} = [field(:).Type];
end

if isempty(obj)
% At this point, since we have already confirmed all the
% Fields have the same dimensions, if one of the Fields are
% empty, then they must all be empty. This means they must
% all be equal.
tf = true;
else
names = [obj(:).Name]';
if any(names ~= namesToCompare, "all")
% Return false early if the field names are not equal.
return;
end

% Field names were equal. Check if their corresponding types
% are equal and return the result.
types = [obj(:).Type];
tf = isequal(types, typesToCompare{:});
end
end
end

methods (Access = private)
Expand Down
103 changes: 103 additions & 0 deletions matlab/test/arrow/type/tField.m
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,108 @@ function TestImmutableProperties(testCase)
testCase.verifyError(@() setfield(field, "Type", arrow.boolean), "MATLAB:class:noSetMethod")
end

function TestIsEqualScalarTrue(testCase)
% Two scalar arrow.type.Field objects are equal if:
%
% 1. Their Name properties are equal
% 2. Their Type properties are equal

f1 = arrow.field("A", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second"));
f2 = arrow.field("A", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second"));
testCase.verifyTrue(isequal(f1, f2));
end

function TestIsEqualScalarFalse(testCase)
% Verifies isequal returns false when expected.
f1 = arrow.field("A", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second"));
f2 = arrow.field("B", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second"));
f3 = arrow.field("A", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Millisecond"));
f4 = arrow.field("A", arrow.time32());

% Name properties are not equal
testCase.verifyFalse(isequal(f1, f2));

% Type properties are not equal
testCase.verifyFalse(isequal(f1, f3));

% Type properties have different class types
testCase.verifyFalse(isequal(f1, f4));

% Compare arrow.type.Field and a string
testCase.verifyFalse(isequal(f1, "A"));
end

function TestIsEqualNonScalarTrue(testCase)
% Two nonscalar arrow.type.Field arrays are equal if:
% 1. They have the same shape
% 2. Their corresponding Field elements are equal

f1 = arrow.field("A", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second"));
f2 = arrow.field("B", arrow.string());
fieldArray1 = [f1 f2 f1; f2 f1 f1];
fieldArray2 = [f1 f2 f1; f2 f1 f1];

testCase.verifyTrue(isequal(fieldArray1, fieldArray2));
testCase.verifyTrue(isequal(fieldArray1, fieldArray2, fieldArray1));
end

function TestIsEqualEmptyFields(testCase)
% Verify isequal returns the expected value when at least one
% of the inputs is empty.

f1 = arrow.type.Field.empty(1, 0);
f2 = arrow.type.Field.empty(0, 1);
f3 = arrow.type.Field.empty(0, 0);
f4 = arrow.field("B", arrow.string());

% Compare two 1x0 Field arrays
testCase.verifyTrue(isequal(f1, f1));

% Compare two 0x1 Field arrays
testCase.verifyTrue(isequal(f2, f2));

% Compare two 0x0 Field arrays
testCase.verifyTrue(isequal(f3, f3));

% Compare 1x0 and 0x1 Field arrays
testCase.verifyFalse(isequal(f1, f2));

% Compare 1x0 and 0x0 Field arrays
testCase.verifyFalse(isequal(f1, f3));

% Compare 0x1 and 0x0 Field arrays
testCase.verifyFalse(isequal(f2, f3));

% Compare 1x0 and 1x1 Field arrays
testCase.verifyFalse(isequal(f1, f4));
end

function TestIsEqualNonScalarFalse(testCase)
% Verifies isequal returns false when expected for non-scalar
% Field arrays.

f1 = arrow.field("A", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second"));
f2 = arrow.field("B", arrow.string());
f3 = arrow.field("B", arrow.date32());
f4 = arrow.field("C", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second"));

fieldArray1 = [f1 f2 f3; f4 f1 f2];
fieldArray2 = reshape(fieldArray1, [3 2]);
fieldArray3 = [f1 f3 f3; f4 f1 f2];
fieldArray4 = [f4 f2 f3; f4 f1 f2];

% They have different shapes
testCase.verifyFalse(isequal(fieldArray1, fieldArray2));
testCase.verifyFalse(isequal(fieldArray1, fieldArray2, fieldArray1));

% Their corresponding elements are not equal - type mismatch
testCase.verifyFalse(isequal(fieldArray1, fieldArray3));

% Their corresponding elements are not equal - name mismatch
testCase.verifyFalse(isequal(fieldArray1, fieldArray4));

% Compare arrow.type.Field array and a string array
testCase.verifyFalse(isequal(f1, strings(size(f1))));
end
end
end

0 comments on commit 3aa7e24

Please sign in to comment.