-
Notifications
You must be signed in to change notification settings - Fork 8
/
DX.Classes.Collections.pas
145 lines (124 loc) · 3.61 KB
/
DX.Classes.Collections.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/// <summary>
/// This unit provides various classes implementing additional functionality
/// for collection-type classes.
/// </summary>
unit DX.Classes.Collections;
interface
uses
System.Classes, System.SysUtils, System.Generics.Defaults, System.Generics.Collections, System.RTTI;
type
/// <summary>
/// TListHelper offers class methods extending TList<T>
/// functionality.
/// </summary>
TListHelper<T> = class(TObject)
protected
class function CompareByProperty(Item1, Item2: T; Const APropertyName: string): integer;
public
/// <summary>
/// RemoveDuplicates removes duplicates (in terms of instances of T) from
/// ASource. Its implementation follows a simple lookup approach and may
/// behave O(n^2).
/// </summary>
/// <param name="AList">
/// A list containing instances of type T.
/// </param>
class procedure RemoveDuplicates(AList: TList<T>);
/// <summary>
/// "Paginates" the List by returing only the elements that belong to the
/// given page.
/// </summary>
/// <returns>
/// Number of total pages
/// </returns>
class function Paginate(AList: TList<T>; APage, APageSize: integer): integer; static;
/// <summary>
/// Sorts the List by the given property of T
/// </summary>
class procedure SortByProperty(List: TList<T>; const APropertyName: string); static;
end;
implementation
uses
System.Math;
{ TListHelper<T> }
class function TListHelper<T>.CompareByProperty(Item1, Item2: T; Const APropertyName: string): integer;
var
Ctx: TRttiContext;
Prop: TRttiProperty;
begin
Ctx := TRttiContext.Create;
try
var
LType := Ctx.GetType(TypeInfo(T));
Prop := LType.GetProperty(APropertyName);
if LType.IsRecord then
raise ENotImplemented.Create('CompareByProperty() not implemented for Records');
var
LItem1 := TObject(Pointer(Addr(Item1))^);
var
LItem2 := TObject(Pointer(Addr(Item2))^);
Result := CompareText(Prop.GetValue(LItem1).AsString, Prop.GetValue(LItem2).AsString);
finally
Ctx.Free;
end;
end;
class procedure TListHelper<T>.SortByProperty(List: TList<T>; const APropertyName: string);
var
Comparer: IComparer<T>;
begin
Comparer := TComparer<T>.Construct(
function(const Left, Right: T): integer
begin
Result := CompareByProperty(Left, Right, APropertyName);
end);
List.Sort(Comparer);
end;
class function TListHelper<T>.Paginate(AList: TList<T>; APage, APageSize: integer): integer;
begin
if APage < 1 then
raise Exception.Create('Page must be larger than 0!');
if APageSize < 1 then
raise Exception.Create('PageSize must be larger than 0!');
var
LCount := AList.Count;
var
LTotalPages := LCount div APageSize;
// APage/LTotalPages are 1-based
if (LCount mod APageSize) > 0 then
begin
inc(LTotalPages);
end;
// APage := Min(APage, LTotalPages);
// LFrom is 0-based
var
LFrom := (APage - 1) * APageSize;
// Alle Elemente vor LFrom entfernen
AList.DeleteRange(0, Min(AList.Count, LFrom));
// Alle Elemente nach einer PageSize entfernen
if AList.Count > APageSize then
begin
AList.DeleteRange(APageSize, AList.Count - APageSize);
end;
result := LTotalPages;
end;
class procedure TListHelper<T>.RemoveDuplicates(AList: TList<T>);
begin
if Assigned(AList) then
begin
var LTempList := TList<T>.Create;
try
for var LItem in AList do
begin
if not LTempList.Contains(LItem) then
begin
LTempList.Add(LItem);
end;
end;
AList.Clear;
AList.AddRange(LTempList);
finally
FreeAndNil(LTempList);
end;
end;
end;
end.