Say you have an array of integer values, for example, pages of a document or years when something happened, like years when new Delphi version was released:
delphiReleased: TArray<integer> = [1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2020, 2021, 2022];
If you would want to display the above years in a user friendly manner as a set of ranges, you could go for:
1995 - 1999, 2001 - 2003, 2005 - 2007, 2009 - 2018, 2020 - 2022
Here’s an algorithm (in a console app code) that does the above
program range_display;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.Generics.Defaults, System.Generics.Collections;
type
TRange = record
Start, Stop : integer;
function ToString : string;
constructor Create(const _start, _stop : integer);
end;
function RangeDisplay(intArray: TArray<integer>) : string; overload;
var
snRange : TRange;
snRangeList : TList<TRange>;
i : integer;
begin
if Length(intArray) = 0 then Exit ('');
TArray.Sort<integer>(intArray);
snRangeList := TList<TRange>.Create;
try
snRange := TRange.Create(intArray[Low(intArray)], intArray[Low(intArray)]);
for i := 1 + Low(intArray) to High(intArray) do
begin
if (intArray[i] = Succ(snRange.Stop)) OR (intArray[i] = snRange.Stop) then
snRange.Stop := intArray[i]
else
begin
snRangeList.Add(snRange);
snRange := TRange.Create(intArray[i], intArray[i]);
end;
end;
snRangeList.Add(snRange);
result := snRangeList.First.ToString;
snRangeList.Delete(0);
for snRange in snRangeList do
result := result + ', ' + snRange.ToString;
finally
snRangeList.Free;
end;
end;
function RangeDisplay(const intList: TList<integer>) : string; overload;
begin
result := RangeDisplay(intList.ToArray);
end;
{$region 'TRange'}
constructor TRange.Create(const _start, _stop: integer);
begin
Start := _start;
Stop := _stop;
end;
function TRange.ToString: string;
begin
if Start = Stop then
result := Start.ToString()
else
result := Format('%s - %s',[Start.ToString, Stop.ToString]);
end;
{$endregion 'TRange'}
const
emptyArray : TArray<integer> = [];
intArray1 : TArray<integer> = [1, 2, 4, 6, 7, 10, 11, 9, 9, 12, 300, 301]; //9 is a duplicate
intArray2 : TArray<integer> = [3, 4, 6, 7, 8, 9, 10, 12, 13, 15, 16];
begin
try
Writeln('emptyArray:' + RangeDisplay(emptyArray));
Writeln('intArray1:' + RangeDisplay(intArray1));
Writeln('intArray2:' + RangeDisplay(intArray2));
ReadLn;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
The result when running the above:
emptyArray: intArray1:1 - 2, 4, 6 - 7, 9 - 12, 300 - 301 intArray2:3 - 4, 6 - 10, 12 - 13, 15 - 16
That’s it.
