The series of increasing prime numbers begins: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, ...

The task applies a filter to the series returning groups of successive primes, (s'primes), that differ from the next by a given value or values.

Example 1: Specifying that the difference between s'primes be 2 leads to the groups:

(3, 5), (5, 7), (11, 13), (17, 19), (29, 31), ...

(Known as Twin primes or Prime pairs)

Example 2: Specifying more than one difference between s'primes leads to groups of size one greater than the number of differences. Differences of 2, 4 leads to the groups:

(5, 7, 11), (11, 13, 17), (17, 19, 23), (41, 43, 47), .... 

In the first group 7 is two more than 5 and 11 is four more than 7; as well as 5, 7, and 11 being successive primes.
Differences are checked in the order of the values given, (differences of 4, 2 would give different groups entirely).

Task

 In each case use a list of primes less than 1_000_000
 For the following Differences show the first and last group, as well as the number of groups found:
 Differences of 2.
 Differences of 1.
 Differences of 2, 2.
 Differences of 2, 4.
 Differences of 4, 2.
 Differences of 6, 4, 2.
 Show output here.

Note: Generation of a list of primes is a secondary aspect of the task. Use of a built in function, well known library, or importing/use of prime generators from other Rosetta Code tasks is encouraged.

references
https://pdfs.semanticscholar.org/78a1/7349819304863ae061df88dbcb26b4908f03.pdf
https://www.primepuzzles.net/puzzles/puzz_011.htm
https://matheplanet.de/matheplanet/nuke/html/viewtopic.php?topic=232720&start=0
 
program Successive_prime_differences;
 
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
  System.SysUtils,
  System.Generics.Collections;
 
function IsPrime(a: UInt64): Boolean;
var
  d: UInt64;
begin
  if (a < 2) then
    exit(False);
 
  if (a mod 2) = 0 then
    exit(a = 2);
 
  if (a mod 3) = 0 then
    exit(a = 3);
 
  d := 5;
 
  while (d * d <= a) do
  begin
    if (a mod d = 0) then
      Exit(false);
    inc(d, 2);
 
    if (a mod d = 0) then
      Exit(false);
    inc(d, 4);
  end;
 
  Result := True;
end;
 
function Primes(const limit: UInt64): TArray<UInt64>;
var
  i: UInt64;
 
  procedure Add(const value: UInt64);
  begin
    SetLength(result, Length(result) + 1);
    Result[Length(result) - 1] := value;
  end;
 
begin
  if limit < 2 then
    exit;
 
  // 2 is the only even prime
  Add(2);
 
  i := 3;
  while i <= limit do
  begin
    if IsPrime(i) then
      Add(i);
    inc(i, 2);
  end;
end;
 
function Commatize(const n: UInt64): string;
var
  str: string;
  digits: Integer;
  i: Integer;
begin
  Result := '';
  str := n.ToString;
  digits := str.Length;
 
  for i := 1 to digits do
  begin
    if ((i > 1) and (((i - 1) mod 3) = (digits mod 3))) then
      Result := Result + ',';
    Result := Result + str[i];
  end;
end;
 
function CheckScan(index: Integer; p: TArray<UInt64>; pattern: array of Integer): Boolean;
var
  i, last: Integer;
begin
  last := Length(pattern) - 1;
  for i := 0 to last do
    if p[index - last + i - 1] + pattern[i] <> p[index - last + i] then
      exit(False);
  Result := True;
end;
 
const
  GroupLabel: array[1..6] of string = ('(2)', '(1)', '(2, 2)', '(2, 4)',
    '(4, 2)', '(6, 4, 2)');
 
var
  limit, start: UInt64;
  c: TArray<UInt64>;
  i, j: UInt64;
  Group: array[1..6] of Tlist<string>;
 
begin
  for i := 1 to 6 do
    Group[i] := Tlist<string>.Create;
 
  limit := Trunc(1e6 - 1);
  c := Primes(limit);
 
  for j := 1 to High(c) do
  begin
    if CheckScan(j, c, [2]) then
      Group[1].Add(format('(%d,%d)', [c[j - 1], c[j]]));
 
    if CheckScan(j, c, [1]) then
      Group[2].Add(format('(%d,%d)', [c[j - 1], c[j]]));
 
    if j > 1 then
    begin
      if CheckScan(j, c, [2, 2]) then
        Group[3].Add(format('(%d,%d,%d)', [c[j - 2], c[j - 1], c[j]]));
 
      if CheckScan(j, c, [2, 4]) then
        Group[4].Add(format('(%d,%d,%d)', [c[j - 2], c[j - 1], c[j]]));
 
      if CheckScan(j, c, [4, 2]) then
        Group[5].Add(format('(%d,%d,%d)', [c[j - 2], c[j - 1], c[j]]));
    end;
 
    if j > 2 then
      if CheckScan(j, c, [6, 4, 2]) then
        Group[6].Add(format('(%d,%d,%d,%d)', [c[j - 3], c[j - 2], c[j - 1], c[j]]));
 
  end;
 
  for i := 1 to 6 do
  begin
    Write(GroupLabel[i], ': first group = ', Group[i].First);
    Writeln(', last group = ', Group[i].last, ', count = ', Group[i].Count);
    Group[i].free;
  end;
 
  readln;
end.
 
 