Delphi 如何在pascal中生成彼此唯一的随机整数

Delphi 如何在pascal中生成彼此唯一的随机整数,delphi,random,integer,Delphi,Random,Integer,我想用pascal编写一个程序,在1和49之间选择6个随机整数。每个数字都应该是唯一的,即不能有'8,22'22'32'37'43',因为'22'是重复的。如何在Delphi中实现这一点 通过使用下面的代码,我可以得到6个介于1-49之间的随机数 for i := 1 to 6 do begin num[i] := random(49) + 1 end {next}; 我会这样做: function Choose(M, N: Integer): TArray<Integ

我想用pascal编写一个程序,在1和49之间选择6个随机整数。每个数字都应该是唯一的,即不能有'8,22'22'32'37'43',因为'22'是重复的。如何在Delphi中实现这一点

通过使用下面的代码,我可以得到6个介于1-49之间的随机数

for i := 1 to 6 do
  begin 
    num[i] := random(49) + 1
  end
{next};

我会这样做:

function Choose(M, N: Integer): TArray<Integer>;
var
  i: Integer;
  Values: TArray<Integer>;
begin
  Assert(M>0);
  Assert(N>=M);

  SetLength(Values, N);
  for i := 0 to N-1 do
    Values[i] := i+1;

  for i := 0 to Min(M-1, N-2) do
    Swap(Values[i], Values[i + Random(N-i)]);

  Result := Copy(Values, 0, M);
end;
  • 将数字1到49放入一个数组中
  • 对阵列执行洗牌
  • 拉出前6个元件
  • 这可能不是最有效的方法,但它很容易实现,容易理解,最重要的是,很容易对采样方法的分布属性进行推理

    对于洗牌,使用洗牌。我用一种通用方法实现了这一点:

    procedure TRandomNumberGenerator.Permute<T>(var Values: array of T);
    var
      i, Count: Integer;
    begin
      Count := Length(Values);
      for i := 0 to Count-2 do
        TGeneric.Swap<T>(Values[i], Values[i + Uniform(Count-i)]);
    end;
    
    当然,您只需要执行循环的前六次迭代,因此非常有效的版本如下:

    function Choose(M, N: Integer): TArray<Integer>;
    var
      i: Integer;
      Values: TArray<Integer>;
    begin
      Assert(M>0);
      Assert(N>=M);
    
      SetLength(Values, N);
      for i := 0 to N-1 do
        Values[i] := i+1;
    
      for i := 0 to Min(M-1, N-2) do
        Swap(Values[i], Values[i + Random(N-i)]);
    
      Result := Copy(Values, 0, M);
    end;
    
    如果你是一个疯狂的表演狂,那么我想你很难战胜这一点:

    type
      TArr6 = array [0..5] of Integer;
      PArr6 = ^TArr6;
      TArr49 = array [0..48] of Integer;
    
    const
      OrderedArr49: TArr49 = (
        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
      );
    
    function Choose6: TArr6;
    var
      i: Integer;
      Values: TArr49;
    begin
      Values := OrderedArr49;
      for i := 0 to high(Result) do begin
        Swap(Values[i], Values[i + Random(Length(Values)-i)]);
      end;
      Result := PArr6(@Values)^;
    end;
    

    我应该说,我怀疑性能将是这里的驱动因素。

    我认为对于一个简单的解决方案,考虑到您想要的值相对较少,而可能的值相对较少,您可以强制执行它

    如果是Perl或PHP,我会使用关联数组,但泛型也可以:

    uses
      System.Generics.Collections;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      i: Integer;
      numbers: TList<Integer>;
      num: Integer;
      output: String;
    begin
      numbers := TList<Integer>.Create;
      try
        // We need six integers
        for i := 1 to 6 do
        begin
          // Generate a "random" integer
          num := Random(49) + 1;
          // Keep going until it isn't in our list
          while numbers.Contains(num) do
          begin
            num := Random(49) + 1;
          end;
          // Add it to the list
          numbers.Add(num);
        end;
        // Display the list
        output := '';
        for num in numbers do
        begin
          output := output + IntToStr(num) + ':';
        end;
        ShowMessage(output);
      finally
        numbers.Free;
      end;
    end;
    
    使用
    系统、泛型、集合;
    程序TForm1.按钮1单击(发送方:TObject);
    变量
    i:整数;
    编号:TList;
    num:整数;
    输出:字符串;
    开始
    编号:=TList.Create;
    尝试
    //我们需要六个整数
    对于i:=1到6 do
    开始
    //生成一个“随机”整数
    num:=随机(49)+1;
    //继续,直到它不在我们的名单上
    而numbers.Contains(num)do
    开始
    num:=随机(49)+1;
    结束;
    //将其添加到列表中
    数字。添加(num);
    结束;
    //显示列表
    输出:='';
    对于num,数字是多少
    开始
    输出:=输出+IntToStr(num)+':';
    结束;
    显示消息(输出);
    最后
    数字。免费;
    结束;
    结束;
    

    这个解决方案可能会引起一些争论,因为有些人可能认为这在理论上是可能永远不会回来的,但考虑到Delphi的PRNG,情况就不是这样了。

    一个非常简单的方法是首先用从0到max-1的所有数值填充一个列表,然后使用
    random(count(list))选择并删除一个随机值
    @500 InternalServerError将执行此操作。那是费舍尔·耶茨。那么我的语言能力比你强;)听起来像是彩票号码生成器:)@NickHodges,因为同一个号码可能会出现不止一次。考虑到洗牌一系列整数是多么容易,我会改为洗牌。我会随时使用非指针版本。@WarrenP我试图覆盖所有的基数!!;-)如果我使用High,我也会使用Low->
    作为I:=Low(结果)到High(结果)do
    uses
      System.Generics.Collections;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      i: Integer;
      numbers: TList<Integer>;
      num: Integer;
      output: String;
    begin
      numbers := TList<Integer>.Create;
      try
        // We need six integers
        for i := 1 to 6 do
        begin
          // Generate a "random" integer
          num := Random(49) + 1;
          // Keep going until it isn't in our list
          while numbers.Contains(num) do
          begin
            num := Random(49) + 1;
          end;
          // Add it to the list
          numbers.Add(num);
        end;
        // Display the list
        output := '';
        for num in numbers do
        begin
          output := output + IntToStr(num) + ':';
        end;
        ShowMessage(output);
      finally
        numbers.Free;
      end;
    end;