In C# Linq would make this super-easy but I am new to using Lists in Delphi and I need some advice.
I have a list of objects stored as TList<IMyInterface>
with each object essentially being a collection of data, e.g.
1, 1, 2, 2, 2, 2, 3, 4, 4, 4
I wish to create a new TList<TList<IMyInterface>>
where the items in the list are grouped such as:
1, 1
2, 2, 2, 2, 2
3
4, 4, 4
What would be the most effective way of doing this in Delphi XE3 (starter edition)?
The easiest would be a set of loops. Using the DeHL or Spring frameworks for Delphi might shorten your code a bit, but not much.
This question about querying generic TList instances using conditions gives a hint on using the Collections from the Spring framework.
My example uses Integer
in stead of your interface type, but it should be easy to adapt.
Below are two methods for splitting, depending if you want each list to start on a changing value, or only for distinct values (like David said: long live TDictionary<Key, Value>
)
I see the difference, I doubled your example:
1, 1, 2, 2, 2, 2, 3, 4, 4, 4, 1, 1, 2, 2, 2, 2, 3, 4, 4, 4
The first algorithm will return these:
1, 1
2, 2, 2, 2
3
4, 4, 4
1, 1
2, 2, 2, 2
3
4, 4, 4
The second these:
1, 1, 1, 1
2, 2, 2, 2, 2, 2, 2, 2
3, 3
4, 4, 4, 4, 4, 4
Here is the example program; only printing requires nested loops.
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.