ðŸŽ‰ Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io ðŸŽ‰

# dgeiger's solution

## to Matrix in the Delphi Pascal Track

Published at Sep 03 2020 · 0 comments
Instructions
Test suite
Solution

Given a string representing a matrix of numbers, return the rows and columns of that matrix.

So given a string with embedded newlines like:

``````9 8 7
5 3 2
6 6 7
``````

representing this matrix:

``````    1  2  3
|---------
1 | 9  8  7
2 | 5  3  2
3 | 6  6  7
``````

your code should be able to spit out:

• A list of the rows, reading each row left-to-right while moving top-to-bottom across the rows,
• A list of the columns, reading each column top-to-bottom while moving from left-to-right.

The rows for our example matrix:

• 9, 8, 7
• 5, 3, 2
• 6, 6, 7

And its columns:

• 9, 5, 6
• 8, 3, 6
• 7, 2, 7

## Testing

In order to run the tests for this track, you will need to install DUnitX. Please see the installation instructions for more information.

If Delphi is properly installed, and `*.dpr` file types have been associated with Delphi, then double clicking the supplied `*.dpr` file will start Delphi and load the exercise/project. `control + F9` is the keyboard shortcut to compile the project or pressing `F9` will compile and run the project.

Alternatively you may opt to start Delphi and load your project via. the `File` drop down menu.

### When Questions Come Up

We monitor the Pascal-Delphi support room on gitter.im to help you with any questions that might arise.

### Submitting Exercises

Note that, when trying to submit an exercise, make sure the exercise file you're submitting is in the `exercism/delphi/<exerciseName>` directory.

For example, if you're submitting `ubob.pas` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/delphi/bob/ubob.pas`.

## Source

Warmup to the `saddle-points` warmup. http://jumpstartlab.com

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you may request help from a mentor.

### uMatrixTests.pas

``````unit uMatrixTests;

interface

uses
DUnitX.TestFramework, System.Generics.Collections;

const
CanonicalVersion = '1.1.0.1';

type

[TestFixture]
TMatrixTest = class(TObject)
private
ExpectedRow : TList<integer>;
procedure CompareArrays(Array1, Array2: TArray<integer>);
public
[Setup]
procedure Setup;

[TearDown]
procedure TearDown;

[Test]
//    [Ignore('Comment the "[Ignore]" statement to run the test')]
procedure extract_row_from_one_number_matrix;

[Test]
[Ignore]
procedure can_extract_row;

[Test]
[Ignore]
procedure extract_row_where_numbers_have_different_widths;

[Test]
[Ignore]
procedure can_extract_row_from_non_square_matrix;

[Test]
[Ignore]
procedure extract_column_from_one_number_matrix;

[Test]
[Ignore]
procedure can_extract_column;

[Test]
[Ignore]
procedure can_extract_column_from_non_square_matrix;

[Test]
[Ignore]
procedure extract_column_where_numbers_have_different_widths;
end;

implementation
uses uMatrix;

procedure TMatrixTest.can_extract_column;
var
CUT: TMatrix;
Expected, Actual : TArray<integer>;
i: Integer;
begin
Expected := ExpectedRow.ToArray;
CUT := TMatrix.Create('1 2 3\n4 5 6\n7 8 9');
Actual := CUT.column(3);
CompareArrays(Expected, Actual);
end;

procedure TMatrixTest.can_extract_column_from_non_square_matrix;
var
CUT: TMatrix;
Expected, Actual : TArray<integer>;
i: Integer;
begin
Expected := ExpectedRow.ToArray;
CUT := TMatrix.Create('1 2 3\n4 5 6\n7 8 9\n8 7 6');
Actual := CUT.column(3);
CompareArrays(Expected, Actual);
end;

procedure TMatrixTest.can_extract_row;
var
CUT: TMatrix;
Expected, Actual : TArray<integer>;
i: Integer;
begin
Expected := ExpectedRow.ToArray;
CUT := TMatrix.Create('1 2\n3 4');
Actual := CUT.Row(2);
CompareArrays(Expected, Actual);
end;

procedure TMatrixTest.can_extract_row_from_non_square_matrix;
var
CUT: TMatrix;
Expected, Actual : TArray<integer>;
i: Integer;
begin
Expected := ExpectedRow.ToArray;
CUT := TMatrix.Create('1 2 3\n4 5 6\n7 8 9\n8 7 6');
Actual := CUT.Row(3);
CompareArrays(Expected, Actual);
end;

procedure TMatrixTest.extract_column_from_one_number_matrix;
var
CUT: TMatrix;
Expected, Actual : TArray<integer>;
i: Integer;
begin
Expected := ExpectedRow.ToArray;
CUT := TMatrix.Create('1');
Actual := CUT.column(1);
CompareArrays(Expected, Actual);
end;

procedure TMatrixTest.extract_column_where_numbers_have_different_widths;
var
CUT: TMatrix;
Expected, Actual : TArray<integer>;
i: Integer;
begin
Expected := ExpectedRow.ToArray;
CUT := TMatrix.Create('89 1903 3\n18 3 1\n9 4 800');
Actual := CUT.column(2);
CompareArrays(Expected, Actual);
end;

procedure TMatrixTest.extract_row_from_one_number_matrix;
var
CUT: TMatrix;
Expected, Actual : TArray<integer>;
i: Integer;
begin
Expected := ExpectedRow.ToArray;
CUT := TMatrix.Create('1');
Actual := CUT.Row(1);
CompareArrays(Expected, Actual);
end;

procedure TMatrixTest.extract_row_where_numbers_have_different_widths;
var
CUT: TMatrix;
Expected, Actual : TArray<integer>;
i: Integer;
begin
Expected := ExpectedRow.ToArray;
CUT := TMatrix.Create('1 2\n10 20');
Actual := CUT.Row(2);
CompareArrays(Expected, Actual);
end;

procedure TMatrixTest.CompareArrays(Array1, Array2: TArray<integer>);
var
i: integer;
begin
Assert.AreEqual(Length(Array1), Length(Array2));
for i := Low(Array1) to High(Array1) do
Assert.AreEqual(Array1[i], Array2[i]);
end;

procedure TMatrixTest.Setup;
begin
ExpectedRow := TList<integer>.Create;
end;

procedure TMatrixTest.TearDown;
begin
ExpectedRow.DisposeOf;
end;

initialization
TDUnitX.RegisterTestFixture(TMatrixTest);
end.``````
``````unit uMatrix;

interface

uses
System.Classes, System.Generics.Collections, System.SysUtils;

type
TMatrix = class
private
FMatrix: TArray<TArray<Integer>>;
FMatrixString: String;
FColumns: Integer;
FRows: Integer;
FRow: Integer;

procedure ExtractRows;
procedure ExtractElements;

public
constructor Create(MatrixString: String);

function Column(ColumnNo: Integer): TArray<Integer>;
function Row(RowNo: Integer): TArray<Integer>;

end;

implementation

{ TMatrix }

function TMatrix.Column(ColumnNo: Integer): TArray<Integer>;
var
Row: Integer;
begin
// Set the length of the result TArray to the number of rows
SetLength(Result, FRows);

// If ColumnNo is outside the range of columms in the matrix (when scaled)
// it can't be processed, so quit.
if (ColumnNo < 1) or (ColumnNo > Length(FMatrix[0])) then
Exit;

// Now, we need to cycle through the rows
for Row := 0 to FRows - 1 do
// adding the element in the specified column to the result.
Result[Row] := FMatrix[Row, ColumnNo - 1];
end;

constructor TMatrix.Create(MatrixString: String);
begin
// Start of by saving the passed string
FMatrixString := Trim(MatrixString);

// Then extract the elements from the string and insert them into the matrix
ExtractRows;
end;

procedure TMatrix.ExtractElements;
var
Elements: TList<Integer>;
Position: Integer;
ElementString: String;
Column: Integer;
begin
// Create the list of elements found
Elements := TList<Integer>.Create;

// Start with no columns in the row - we'll figure out the size later
FColumns := 0;

// We look for elements until the string is empty
while Length(FMatrixString) > 0 do
begin
// Look for a space between elements
Position := Pos(' ', FMatrixString);

if Position = 0 then
// There was no space, so this is the last element
begin
// Save it's value
ElementString := FMatrixString;

// and empty the string, signaling that we're done here.
FMatrixString := '';
end
else
// We found the gap between two elements
begin
// Save the element's value
ElementString := Copy(FMatrixString, 1, Position - 1);

// Remove the element from the string
Delete(FMatrixString, 1, Position);

// Make sute there aren't any spaces in the front of the string
FMatrixString := Trim(FMatrixString);
end;

// Add the element to the string. In the real world, I'd be checking
// to make sure the element was an integer, but I'm omitting it for
// this exercixe.

// Add to the column count
Inc(FColumns);
end;

// Set the matrix row's size
SetLength(FMatrix[FRow], FColumns);

// Now it's time to put the elements into the matrix row
for Column := 0 to FColumns - 1 do
begin
// Set the cell to the element value
FMatrix[FRow, Column] := Elements[0];

// and remove the element value from the list.
Elements.Delete(0);
end;

// Clean up
Elements.Destroy;
end;

procedure TMatrix.ExtractRows;
var
Rows: TStringList;
Position: Integer;
RowString: String;
Index: Integer;
begin
// Create the list of rows found
Rows := TStringList.Create;

// Start with no rows in the matrix - we'll figure out the size later
FRows := 0;

// We look for rows until the string is empty
while Length(FMatrixString) > 0 do
begin
// Look for the new-line sequence between rows
Position := Pos('\', FMatrixString);

// There was no new-line sequence, so this is the last row
if Position = 0 then
begin
// Save it's value
RowString := FMatrixString;

// and empty the string, signaling that we're done here.
FMatrixString := '';
end
else
// There was no new-line sequence, so this is the last element
begin
// Save the row text for later processing
RowString := Copy(FMatrixString, 1, Position - 1);

// and remove it from the string.
Delete(FMatrixString, 1, Position + 1);

// Make sute there aren't any spaces in the front of the string
FMatrixString := Trim(FMatrixString);
end;

// Add the row text to the list of rows

// Increment the row count
Inc(FRows);
end;

// Now that we know how many rows are in the matrix, set it's length
SetLength(FMatrix, FRows);

// Now let's break the rows into columns, and put the cell values in the matrix
for Index := 0 to Rows.Count - 1 do
begin
// Set which row is being processed
FRow := Index;

// Get it's string
FMatrixString := Rows[Index];

// and put the elements into the matrix.
ExtractElements;
end;

// Clean up
Rows.Destroy;
end;

function TMatrix.Row(RowNo: Integer): TArray<Integer>;
var
ColumnNo: Integer;
begin
// Set the length of the result TArray to the number of columns
SetLength(Result, FColumns);

// If RowNo is outside the range of rows in the matrix (when scaled)
// it can't be processed, so quit.
if (RowNo < 1) or (RowNo > Length(FMatrix)) then
Exit;

// Now, we need to cycle through the columns
for ColumnNo := 0 to FColumns - 1 do
// adding the element in the specified row to the result.
Result[ColumnNo] := FMatrix[RowNo - 1, ColumnNo];
end;

end.``````