delphi-collを使ってみる(1)

delphi-collはジェネリックを用いたコレクションのクラスライブラリです。

標準ライブラリのGenerics.Collectionsにはない便利な機能が追加されています。

delphi-collのCollections.Lists.TList<T>を使ってみました。

■Aggregateメソッド

Aggregateメソッドは要素に対して順番に引数の関数を実行して、結果を返します。

最初に先頭の要素と次の要素を引数にして関数を実行します。
2回目以降のループでは、前の関数の実行結果と次の要素を引数にして関数を実行します。
最後の要素まで繰り返し、最後の値を返します。

次のコードはリストの要素の合計値を出力します。

uses
  Collections.Lists
var
  NumList: TList<Integer>;
  Total: Integer;
begin
  NumList := TList<Integer>.Create();
  NumList.Add(2);
  NumList.Add(4);
  NumList.Add(1);
  NumList.Add(3);

  Total := NumList.Aggregate(
    function(Sum, Val: Integer): Integer
    begin
      Exit(Sum + Val)
    end
  );
  WriteLn(Total); //=> 10

■Allメソッド、Anyメソッド

Allメソッドは、要素に対して引数の関数を実行し、すべての要素がTrueの場合にTrueを返します。
1つでもFalseの要素があればFalseを返します。

Anyメソッドは、要素に対して引数の関数を実行し、すべての要素がFalseの場合にFalseを返します。
1つでもTrueの要素があればTrueを返します。

次のコードはリストが条件を満たす時は’OK’と出力します。

var
  NumList: TList<Integer>;
begin
  NumList := TList<Integer>.Create();
  NumList.Add(2);
  NumList.Add(4);
  NumList.Add(1);
  NumList.Add(3);

  //すべての要素が0より大きいか
  if NumList.All(
    function(Val: Integer): Boolean begin Exit(Val > 0); end) then
  begin
     WriteLn('OK');
  end;

  //3より大きい要素があるか
  if NumList.Any(
    function(Val: Integer): Boolean begin Exit(Val > 3); end) then
  begin
     WriteLn('OK');
  end;

■Minメソッド、Maxメソッド

Minメソッドは比較関数で比較して最も値が小さい要素を返します。

Maxメソッドは比較関数で比較して最も値が大きい要素を返します。

比較関数はリストのコンストラクタで指定します。

次のコードは人物リストの中から生年月日の最も新しい人物と最も古い人物を出力します。

type
  TPerson = record
    FName: string;
    FBirthDate: TDate;
    constructor Create(const AName: string; const ABirthDate: TDate);
  end;

  //生年月日で比較する比較関数
  TPersonAgeComparer = class(TCustomComparer<TPerson>)
  public
    function Compare(const Left, Right: TPerson): Integer; override;
    function Equals(const Left, Right: TPerson): Boolean; override;
    function GetHashCode(const Value: TPerson): Integer; override;
  end;

constructor TPerson.Create(const AName: string; const ABirthDate: TDate);
begin
  FName := AName;
  FBirthDate := ABirthDate;
end;

function TPersonAgeComparer.Compare(const Left, Right: TPerson): Integer;
begin
  Result := DateUtils.CompareDate(Left.FBirthDate, Right.FBirthDate);
end;

function TPersonAgeComparer.Equals(const Left, Right: TPerson): Boolean;
begin
  Result := DateUtils.SameDate(Left.FBirthDate, Right.FBirthDate);
end;

function TPersonAgeComparer.GetHashCode(const Value: TPerson): Integer;
begin
  Result := Trunc(Value.FBirthDate);
end;

procedure Main;
var
  PersonList: TList<TPerson>;
  Comparer: TPersonAgeComparer;
  Person: TPerson;
begin
  Comparer := TPersonAgeComparer.Create;
  PersonList := TList<TPerson>.Create(TRules<TPerson>.Custom(Comparer));
  PersonList.Add(TPerson.Create('John', EncodeDate(1984, 1,  4)));
  PersonList.Add(TPerson.Create('Mary', EncodeDate(1955, 4, 11)));
  PersonList.Add(TPerson.Create('Ken',  EncodeDate(2001, 8, 23)));
  PersonList.Add(TPerson.Create('Lidia',EncodeDate(1978, 3, 10)));

  //生年月日が最も新しい人物
  Person := PersonList.Max;
  WriteLn(Person.FName, ' ', DateToStr(Person.FBirthDate));
  //=> Ken 2001/08/23

  //生年月日が最も古い人物
  Person := PersonList.Min;
  WriteLn(Person.FName, ' ', DateToStr(Person.FBirthDate));
  //=> Mary 1955/04/11

■FirstWhereメソッド、FirstWhereNotメソッド

FirstWhereメソッドは条件に該当する最初の要素を返します。

FirstWhereNotメソッドは条件に該当しない最初の要素を返します。

次のコードはリストの中から生年月日が2000年以降である最初の人物と生年月日が2000年以降でない最初の人物を取得します。

var
  PersonList: TList<TPerson>;
  Person: TPerson;
begin
  PersonList := TList<TPerson>.Create;
  PersonList.Add(TPerson.Create('John', EncodeDate(1984, 1,  4)));
  PersonList.Add(TPerson.Create('Mary', EncodeDate(1955, 4, 11)));
  PersonList.Add(TPerson.Create('Ken',  EncodeDate(2001, 8, 23)));
  PersonList.Add(TPerson.Create('Lidia',EncodeDate(1978, 3, 10)));

  //生年月日が2000年以降である最初の人物
  Person := PersonList.FirstWhere(
    function(P: TPerson):Boolean begin
      Exit(CompareDate(EncodeDate(2000, 1, 1), P.FBirthDate) = LessThanValue)
    end);
  WriteLn(Person.FName, ' ', DateToStr(Person.FBirthDate));
  //=> Ken 2001/08/23

  //生年月日が2000年以降でない最初の人物
  Person := PersonList.FirstWhereNot(
    function(P: TPerson):Boolean begin
      Exit(CompareDate(EncodeDate(2000, 1, 1), P.FBirthDate) = LessThanValue)
    end);
  WriteLn(Person.FName, ' ', DateToStr(Person.FBirthDate));
  //=> John 1984/01/04

■FirstWhereLowerメソッド、FirstWhereGreaterメソッド、FirstWhereBetweenメソッド

FirstWhereLowerメソッドは引数の値以下の最初の要素を返します。

FirstWhereGreaterメソッドは引数の値以上の最初の要素を返します。

FirstWhereBetweenメソッドは第1引数以上、第2引数以下の最初の要素を返します。

var
  NumList: TList<Integer>;
  Num: Integer;
begin
  NumList := TList<Integer>.Create();
  NumList.Add(2);
  NumList.Add(4);
  NumList.Add(1);
  NumList.Add(3);

  //3以下の最初の要素
  Num := NumList.FirstWhereLower(3);
  WriteLn(Num); //=> 2

  //3以上の最初の要素
  Num := NumList.FirstWhereGreater(3);
  WriteLn(Num); //=> 4

  //3以上4以下
  Num := NumList.FirstWhereBetween(3, 4);
  WriteLn(Num); //=> 4

■WhereLowerメソッド、WhereGreaterメソッド、WhereBetweenメソッド

WhereLowerメソッドは引数未満の要素を返します。

WhereGreaterメソッドは引数より大きい要素を返します。

WhereBetweenメソッドは引数の間の要素を返します。

var
  NumList: TList<Integer>;
  Num: Integer;
begin
  NumList := TList<Integer>.Create();
  NumList.Add(2);
  NumList.Add(4);
  NumList.Add(1);
  NumList.Add(3);

  //3以下の要素
  for Num in NumList.WhereLower(3) do
    WriteLn(Num); //=> 2,1

  //3以上の要素
  for Num in NumList.WhereGreater(3) do
    WriteLn(Num); //=> 4

  //3以上4以下
  for Num in NumList.WhereBetween(2, 4) do
    WriteLn(Num); //=> 2,4,3

■Distinctメソッド

Distinctはリストから重複する要素を除いた要素を返します。

var
  NumList: TList<Integer>;
  Num: Integer;
begin
  NumList := TList<Integer>.Create();
  NumList.Add(2);
  NumList.Add(4);
  NumList.Add(1);
  NumList.Add(3);
  NumList.Add(2);
  NumList.Add(4);
  NumList.Add(1);

  for Num in NumList.Distinct do
    WriteLn(Num); //=> 2 4 1 3

■Orderedメソッド

Orderedメソッドは、比較関数で並び替えた新しいリストを返します。

var
  PersonList: TList<TPerson>;
  Person: TPerson;
begin
  PersonList := TList<TPerson>.Create;
  PersonList.Add(TPerson.Create('John', EncodeDate(1984, 1,  4)));
  PersonList.Add(TPerson.Create('Mary', EncodeDate(1955, 4, 11)));
  PersonList.Add(TPerson.Create('Ken',  EncodeDate(2001, 8, 23)));
  PersonList.Add(TPerson.Create('Lidia',EncodeDate(1978, 3, 10)));

  for Person in PersonList.Ordered(
    function(const Right, Left: TPerson): Integer
    begin
      Exit(CompareStr(Right.FName, Left.FName));
    end) do
    WriteLn(Person.FName);
  //=> John Ken Lidia Mary

■Concatメソッド

Concatメソッドは引数の要素を結合した新しいリストを返します。

var
  List1, List2: TList<Integer>;
  Num: Integer;
begin
  List1 := TList<Integer>.Create;
  List1.Add(1);
  List1.Add(5);
  List1.Add(3);
  List2 := TList<Integer>.Create;
  List2.Add(5);
  List2.Add(4);
  List2.Add(3);

  for Num in List1.Concat(List2) do
    WriteLn(Num);
  //=> 1 5 3 5 4 3

■Unionメソッド

Unionメソッドは重複しない要素を結合した新しいリストを返します。

var
  List1, List2: TList<Integer>;
  Num: Integer;
begin
  List1 := TList<Integer>.Create;
  List1.Add(1);
  List1.Add(5);
  List1.Add(3);
  List2 := TList<Integer>.Create;
  List2.Add(5);
  List2.Add(4);
  List2.Add(3);

  for Num in List1.Union(List2) do
    WriteLn(Num);
  //=> 1 5 3 4

■Excludeメソッド

Excludeメソッドは引数に存在しない要素を持つ新しいリストを返します。

var
  List1, List2: TList<Integer>;
  Num: Integer;
begin
  List1 := TList<Integer>.Create;
  List1.Add(1);
  List1.Add(5);
  List1.Add(3);
  List2 := TList<Integer>.Create;
  List2.Add(5);
  List2.Add(4);
  List2.Add(3);

  for Num in List1.Exclude(List2) do
    WriteLn(Num);
  //=> 1

■Intersectメソッド

Intersectメソッドは重複する要素を持つ新しいリストを返します。

var
  List1, List2: TList<Integer>;
  Num: Integer;
begin
  List1 := TList<Integer>.Create;
  List1.Add(1);
  List1.Add(5);
  List1.Add(3);
  List2 := TList<Integer>.Create;
  List2.Add(5);
  List2.Add(4);
  List2.Add(3);

  for Num in List1.Intersect(List2) do
    WriteLn(Num);
  //=> 5 3

次回「delphi-collを使ってみる(2)」に続きます。

コメント

  1. Pingback: delphi-collを使ってみる(2) « 山本隆の開発日誌

  2. Pingback: ページが見つかりませんでした « 山本隆の開発日誌

  3. Pingback: delphi-collを使ってみる(4) C#のクエリメソッドと比較する « 山本隆の開発日誌

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください