Powershell:生成唯一的半随机数字字符串

Powershell: generate unique semi random numeric strings

要求:生成 10k 个唯一数字,由序号(16 位)和随机数字字符串(4 位)组成。选择的武器是 Powershell,因为它是我了解的唯一工具。

遇到的问题:

  1. 使用以下方法生成 10k 个序列号:1400000000000000..1400000000010000 并放入变量中。错误:Int32
  2. 的值太大
  3. 通过 Get-Random -Minimum 0001 -Maximum 9999 生成 10k 个 4 位数字并将它们放入变量中。我只设法获得1个随机数。
  4. 使用 Join-Object 组合两个变量(或者至少我希望这样做)

如何组合这 3 个命令来获得上面指定的半随机数列表?或者有没有更简单的方法可以达到同样的效果?

创建唯一序列的经典算法是将所有值放入一个数组中。选择一个值。将数组的最后一个值移动到您刚刚选择该值的位置。然后将数组的大小减一。这会创建数组的副本,因此如果有很多值,请注意调整数组大小所导致的额外成本。

一个从 0 到 19 打乱值的例子是这样的,

$rnd = @()
$arr = 0..19
$tail = $arr.Length-1

do {
    $pick = get-random -min 0 -max $tail
    $rnd += $arr[$pick]
    $arr[$pick] = $arr[$tail]

    $tail--
} while($tail -gt 0)
$rnd += $arr[0]
# Uncomment the next statement to print shuffled array
# $rnd -join ', '

由于该值不适合 int32,请使用 int64。要添加打乱后的值,循环的工作方式如下,

$big = @()
$seed = [int64]1400000000000000

$rnd | % {
  $big += $seed + $_
}
$big

输出

PS C:\> $big
1400000000000015
1400000000000006
1400000000000010
1400000000000017
1400000000000009
1400000000000004
1400000000000005
1400000000000016
1400000000000014
1400000000000003
1400000000000001
1400000000000002
1400000000000013
1400000000000011
1400000000000012
1400000000000019
1400000000000000
1400000000000007
1400000000000008
1400000000000018
(0..10000).ForEach{ '14000000000{0:00000}{1:0000}' -f $_, (Get-Random 10000) }

结果:

14000000000000004965
14000000000000010114
14000000000000026382
14000000000000038644
14000000000000045435
14000000000000052051
14000000000000061801
14000000000000077046
14000000000000087791
14000000000000098090
14000000000000102712
....

解释:

  • 使用 Format Operator (-f) to format the string, like '14000000000{0:00000}{1:0000}'. For details, see composite formatting.
  • 您不必将整个 16 位数字放在 [int32] 中,只需从 0..1000 开始计算,前导零最多 5 位 ({0:00000}),并在其前面加上前缀14000000000
  • 在第二个占位符 ({1:0000}) 中,放置一个新的随机数,前导零最多 4 位

提供了一个优雅的解决方案。

让我通过分别解决第 1 点和第 2 点来补充它:

回复 1.

..range operator supports only [int] (System.Int32) (numeric) endpoints (incidentally, the same applies to LINQ's Range方法)。

您可以使用 .ForEach() 数组方法解决该问题,如 iRon 的回答中所示。

# Returns a collection of [long] (System.Int64) values.
(0..10000).ForEach({ 1400000000000000 + $_ })

回复 2.

PowerShell [Core] 现在支持 Get-Random-Count 参数,允许您在指定范围内请求给定数量的随机数。

# PowerShell [Core] only
# Note that there's no point in specifying leading zeros (0001).
# The output will be an array of unformatted [int] (System.Int32) values
kRandomNums = Get-Random -Count 10000 -Minimum 1 -Maximum 9999

注意:-Maximum 值(与 -Minimum 不同)不包含 ;即可以返回的最高随机数是1低,9998.

Windows PowerShell 中,您必须循环调用 Get-Random

# Windows PowerShell
kRandomNums = foreach ($i in 1..10000) { Get-Random -Minimum 1 -Maximum 9999 }

在循环中调用 cmdlet 的开销很大;您可以直接使用 System.Random .NET class 显着加快速度:

$rnd = [Random]::new()
kRandomNums = foreach ($i in 1..10000) { $rnd.Next(1, 9999) }

类似于优雅和接受这里的答案是一种生成适用于SMBIOS或机箱序列号的26位序列号的方法(例如在创建虚拟机时):

"{0:####-####-####-####}-{1:####-####-##}" -f (Get-Random -Minimum 1000000000000000 -Maximum 9999999999999999),(Get-Random -Minimum 1000000000 -Maximum 9999999999)

样本输出结果如下:

5682-4527-3132-4212-5548-2660-46
6433-6848-9306-5822-1601-7101-98
6986-6609-3112-9326-3662-7689-92

参考资料