Аналог itertools.permutations(iterable, r=None) для delphi

Есть ли у кого-то варианты, как написать такую же функцию, но на делфи. В официальной документации по python имеется yield, которого нет в делфи. Код функции на python:

def permutations(iterable, r=None):
    # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
    # permutations(range(3)) --> 012 021 102 120 201 210
    pool = tuple(iterable)
    n = len(pool)
    r = n if r is None else r
    if r > n:
        return
    indices = list(range(n))
    cycles = list(range(n, n-r, -1))
    yield tuple(pool[i] for i in indices[:r])
    while n:
        for i in reversed(range(r)):
            cycles[i] -= 1
            if cycles[i] == 0:
                indices[i:] = indices[i+1:] + indices[i:i+1]
                cycles[i] = n - i
            else:
                j = cycles[i]
                indices[i], indices[-j] = indices[-j], indices[i]
                yield tuple(pool[i] for i in indices[:r])
                break
        else:
            return

Ответы (1 шт):

Автор решения: MBo

Если нужны просто перестановки в лексикографическом порядке, то надо найти алгоритм next_permutation (с переворотом суффикса) и реализовать его.

itertools.permutations может выдавать ещё сочетания (когда r назначено), но их при необходимости нетрудно получить, используя начальный массив из n-r нулей и r единиц.

Пример

procedure Swap(var A: TArray<Byte>; l, r: Integer);
var
  t: Byte;
begin
  t := A[l];
  A[l] := A[r];
  A[r] := t;
end;

function next_perm(var A: TArray<Byte>): Boolean;
var
  i, j: Integer;
  t: Byte;
begin
  i := High(A);
  while (i > 0) and (A[i - 1] >= A[i]) do
    Dec(i);
  if (i <= 0) then
     Exit(False);

  j := High(A);
  while A[j] <= A[i - 1] do
    Dec(j);
  Swap(A, i - 1, j);

  j := High(A);
  while (i < j)  do begin
    Swap(A, i, j);
    Inc(i);
    Dec(j);
  end;
  Result := True;
end;

function ArrToStr(const A: TArray<Byte>): string;
var
  i: Integer;
begin
  Result := '';
  for i := 0 to High(A) do
    Result := Result + A[i].ToString + ' ';
end;

var
  A: TArray<Byte>;
  i: Integer;
  s: string;
begin
  A := [1,2,3];
  repeat
    Memo1.Lines.Add(ArrToStr(A))
  until not next_perm(A);

1 2 3 
1 3 2 
2 1 3 
2 3 1 
3 1 2 
3 2 1 
→ Ссылка