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.