Skip to content

Latest commit

 

History

History
132 lines (101 loc) · 4.38 KB

File metadata and controls

132 lines (101 loc) · 4.38 KB

FindAll<T> class method

Project: Array Utilities Unit

Unit: DelphiDabbler.Lib.ArrayUtils

Record: TArrayUtils

Applies to: ~>0.1

type
  TConstraint<T> = reference to function (const AElem: T): Boolean;
  TConstraintEx<T> = reference to function (const AElem: T;
    const AIndex: Integer; const AArray: array of T): Boolean;

class function FindAll<T>(const A: array of T;
  const AConstraint: TConstraint<T>): TArray<T>;
  overload; static;

class function FindAll<T>(const A: array of T;
  const AConstraint: TConstraintEx<T>): TArray<T>;
  overload; static;

Description

Finds all the elements of an array for which a given constraint function returns True.

Parameters:

  • A - Array to be checked.

  • AConstraint - Constraint function called for each element of A. Returns True if the element meets the required criteria or False otherwise. AConstraint must be a function of type TConstraint<T> or TConstraintEx<T>.

    Parameter(s):

    • AElem - The current array element to be tested.
    • AIndex - The index of AElem in A. (TConstraintEx<T> only.)
    • AArray - Reference to the array containing AElem. (TConstraintEx<T> only.)

    Returns:

    • True if AElem meets the required criteria, False otherwise.

Returns:

  • Array containing all the elements A for which AConstraint returns True. Will be empty if no such elements exist.

Note

The TConstraint<T> overload is all you need for most purposes. However there are cases where it is useful to have access to the whole array or the element's index within the array, which is the reason the TConstraintEx<T> overload is provided.

Examples

Example #1

The first example finds the all the elements of an integer array that are ≥ 4. We only need the simple TConstraint<T> overload.

procedure FindAll_Eg1;
var
  A, B, Got, Expected: TArray<Integer>;
  Constraint: TArrayUtils.TConstraint<Integer>;
begin
  A := TArray<Integer>.Create(1, 2, 3, 4, 5, 3);
  B := TArray<Integer>.Create(1, 2, 3);
  Constraint := function (const AElem: Integer): Boolean
    begin
      Result := AElem >= 4;
    end;
  Got := TArrayUtils.FindAll<Integer>(A, Constraint);
  Expected := TArray<Integer>.Create(4, 5);
  Assert(TArrayUtils.Equal<Integer>(Expected, Got)); // using default comparer
  Got := TArrayUtils.FindAll<Integer>(B, Constraint);
  Assert(Length(Got) = 0);  // nothing found
end;

Example #2

The second example finds the all the local maxima in an array of integers. To do this we need to be able to access the array element before and after a given element. Therefore the TConstraintEx<T> overload of FindAll<T> is required.

procedure FindAll_Eg2;
var
  IsLocalMaxElem: TArrayUtils.TConstraintEx<Integer>;
  A, B, Got, Expected: TArray<Integer>;
begin
  IsLocalMaxElem :=
    function (const AElem: Integer; const AIndex: Integer;
      const A: array of Integer): Boolean
    begin
      if Length(A) = 0 then
        // no local maxima in an empty array
        Exit(False);
      if Length(A) = 1 then
        // the only element in a 1 element array is considered to be a maximum
        Exit(True);
      // Length(A) >= 2
      if (AIndex = 0) then
        // 1st elem: peak if next elem smaller
        Result := A[Succ(AIndex)] < AElem
      else if AIndex = Pred(Length(A)) then
        // last elem: peak if previous elem smaller
        Result := A[Pred(AIndex)] < AElem
      else
        // not 1st or last: peak if > than elems on either side
        Result := (A[Succ(AIndex)] < AElem) and (A[Pred(AIndex)] < AElem);
    end;

  A := TArray<Integer>.Create(1, 2, 3, 2, 3, 5, 1);
  Got := TArrayUtils.FindAll<Integer>(A, IsLocalMaxElem);
  Expected := TArray<Integer>.Create(3, 5);
  Assert(TArrayUtils.Equal<Integer>(Expected, Got));

  B := TArray<Integer>.Create(1, 1, 1, 1);
  Got := TArrayUtils.FindAll<Integer>(B, IsLocalMaxElem);
  Expected := TArray<Integer>.Create();
  Assert(TArrayUtils.Equal<Integer>(Expected, Got));
end;

See Also