【问题标题】:How can read grouped data from a TList<> in Delphi如何从 Delphi 中的 TList<> 读取分组数据
【发布时间】:2012-10-02 01:23:15
【问题描述】:

在 C# 中,Linq 会使这变得超级简单,但我是在 Delphi 中使用列表的新手,我需要一些建议。

我有一个存储为TList&lt;IMyInterface&gt; 的对象列表,每个对象本质上都是一个数据集合,例如

1, 1, 2, 2, 2, 2, 3, 4, 4, 4 

我希望创建一个新的TList&lt;TList&lt;IMyInterface&gt;&gt;,其中列表中的项目被分组,例如:

1, 1 
2, 2, 2, 2, 2 
3 
4, 4, 4 

在 Delphi XE3(入门版)中最有效的方法是什么?

【问题讨论】:

  • 我会使用字典来收集这些组。没有什么比 Delphi 中的 Linq 更流畅了。
  • +1 为TDictionaryTList&lt;&gt;

标签: delphi tlist delphi-xe3


【解决方案1】:

最简单的方法是一组循环。为 Delphi 使用 DeHL 或 Spring 框架可能会稍微缩短您的代码,但不会太多。

This question 关于使用条件查询通用 TList 实例给出了使用 Spring 框架中的集合的提示。

My example 使用Integer 代替你的接口类型,但它应该很容易适应。

以下是两种拆分方法,具体取决于您是希望每个列表从变化的值开始,还是仅针对不同的值(如大卫所说:万岁TDictionary&lt;Key, Value&gt;

我看到了区别,我把你的例子翻了一番:

1, 1, 2, 2, 2, 2, 3, 4, 4, 4, 1, 1, 2, 2, 2, 2, 3, 4, 4, 4

第一个算法将返回这些:

1, 1
2, 2, 2, 2
3
4, 4, 4
1, 1
2, 2, 2, 2
3
4, 4, 4

第二个:

1, 1, 1, 1
2, 2, 2, 2, 2, 2, 2, 2
3, 3
4, 4, 4, 4, 4, 4

这是示例程序;只有打印需要嵌套循环。

program SplitListOfIntegersIntoSublists;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  System.Generics.Collections;

type
  TIntegerList = TList<Integer>;
  TIntegerListList = TList<TIntegerList>;
  TMain = class(TObject)
  private
    class function AddNewIntegerList(IntegerListList: TIntegerListList): TIntegerList;
    class procedure AddValues(AllIntegers: TIntegerList);
    class procedure Fill_NewListForEachValueChange(const AllIntegers: TIntegerList; const IntegerListList: TIntegerListList);
    class procedure Fill_NewListForDistinctValues(const AllIntegers: TIntegerList; const IntegerListList: TIntegerListList);
    class procedure Free(const IntegerListList: TIntegerListList);
    class procedure Print(const IntegerList: TIntegerList); overload;
    class procedure Print(const IntegerListList: TIntegerListList); overload;
  public
    class procedure Run;
  end;

class function TMain.AddNewIntegerList(IntegerListList: TIntegerListList): TIntegerList;
begin
  Result := TIntegerList.Create;
  IntegerListList.Add(Result);
end;

class procedure TMain.AddValues(AllIntegers: TIntegerList);
begin
// 1, 1, 2, 2, 2, 2, 3, 4, 4, 4
  AllIntegers.Add(1);
  AllIntegers.Add(1);
  AllIntegers.Add(2);
  AllIntegers.Add(2);
  AllIntegers.Add(2);
  AllIntegers.Add(2);
  AllIntegers.Add(3);
  AllIntegers.Add(4);
  AllIntegers.Add(4);
  AllIntegers.Add(4);
end;

class procedure TMain.Fill_NewListForEachValueChange(const AllIntegers: TIntegerList; const IntegerListList: TIntegerListList);
var
  IntegerList: TIntegerList;
  Value: Integer;
begin
  for Value in AllIntegers do
  begin
    if (IntegerListList.Count = 0) or (Value <> IntegerList.First) then
      IntegerList := AddNewIntegerList(IntegerListList);
    IntegerList.Add(Value);
  end;
end;

class procedure TMain.Fill_NewListForDistinctValues(const AllIntegers: TIntegerList; const IntegerListList:
    TIntegerListList);
type
  TIntegerListDictionary = TDictionary<Integer, TIntegerList>;
var
  IntegerListDictionary: TIntegerListDictionary;
  IntegerList: TIntegerList;
  Value: Integer;
begin
  IntegerListDictionary := TIntegerListDictionary.Create();
  for Value in AllIntegers do
  begin
    if IntegerListDictionary.ContainsKey(Value) then
      IntegerList := IntegerListDictionary[Value]
    else
    begin
      IntegerList := AddNewIntegerList(IntegerListList);
      IntegerListDictionary.Add(Value, IntegerList);
    end;
    IntegerList.Add(Value);
  end;
end;

class procedure TMain.Free(const IntegerListList: TIntegerListList);
var
  IntegerList: TIntegerList;
begin
  for IntegerList in IntegerListList do
    IntegerList.Free;
  IntegerListList.Free;
end;

class procedure TMain.Print(const IntegerList: TIntegerList);
var
  Value: Integer;
  First: Boolean;
begin
  First := True;
  for Value in IntegerList do
  begin
    if not First then
      Write(', ');
    Write(Value);
    First := False;
  end;
  Writeln;
end;

class procedure TMain.Print(const IntegerListList: TIntegerListList);
var
  IntegerList: TIntegerList;
begin
  for IntegerList in IntegerListList do
    Print(IntegerList);
  Writeln;
end;

class procedure TMain.Run;
var
  AllIntegers: TIntegerList;
  IntegerListList: TIntegerListList;
begin
  AllIntegers := TIntegerList.Create();
  try
    AddValues(AllIntegers);
    Print(AllIntegers);

    IntegerListList := TIntegerListList.Create();
    try
      Fill_NewListForEachValueChange(AllIntegers, IntegerListList);
      Print(IntegerListList);
    finally
      Free(IntegerListList);
    end;

    AddValues(AllIntegers);
    Print(AllIntegers);

    IntegerListList := TIntegerListList.Create();
    try
      Fill_NewListForEachValueChange(AllIntegers, IntegerListList);
      Print(IntegerListList);
    finally
      Free(IntegerListList);
    end;

    Print(AllIntegers);

    IntegerListList := TIntegerListList.Create();
    try
      Fill_NewListForDistinctValues(AllIntegers, IntegerListList);
      Print(IntegerListList);
    finally
      Free(IntegerListList);
    end;
  finally
    AllIntegers.Free;
  end;
end;

begin
  try
    TMain.Run();
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

【讨论】:

  • 我认为一些算法大纲会有所帮助。仅仅说“使用一组循环”可能不够具体。
  • 我一回到家就可以使用具有泛型的机器。
  • 非常感谢您花时间编写这个示例 Jeroen,它对您有很大帮助。自从我的原始帖子以来,我使用 TDictionary 制作了一个类似的功能(根据大卫的建议),但是您的示例通过非常有用的附加功能对其进行了扩展。我有一些关于释放内存的问题,但我认为发布一个单独的问题更合适,这样我就可以详细解释这些场景。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-08
  • 1970-01-01
  • 2011-08-13
  • 1970-01-01
  • 2023-03-21
  • 2023-03-07
相关资源
最近更新 更多