【问题标题】:How to generate unique numbers for list items如何为列表项生成唯一编号
【发布时间】:2015-01-16 14:57:50
【问题描述】:

我在名为list.txt 的文件中有一个长长的值列表,我想为文件文本文件中的每个项目生成一个随机唯一编号。如果该项目多次出现,它将具有相同的唯一 ID

例如,list.txt 将是:

may-111
may-111
rob-222
kim-456
may-111

我希望能够为每个项目分配一个随机数。如果该项目多次出现,那么它将具有相同的唯一 ID 号,因此预期的输出应该是:-

may-111 - 789
may-111 - 789
rob-222 - 365
kim-456 - 641
may-111 - 789

我尝试生成一个随机数列表并保存到一个新的文本文件,然后将pastejoin 新的文本文件保存到list.txt

paste -d list.txt random.txt

目前,输出不保留唯一 ID,如果同名出现多次,则它具有不同的 ID。

【问题讨论】:

  • 你希望这是一个 awk 脚本吗?
  • 您希望数字是随机的还是唯一的?任何一件事情都是微不足道的,但尝试两者都做可能会导致脚本运行数月,等待随机数生成器提供一个尚未使用的数字..

标签: bash shell awk sed


【解决方案1】:

你可以使用这个 awk:

awk '!seen[$1]{seen[$1] = rand() * 1000000} {print $0 " - " seen[$1]}' file
may-111 - 840188
may-111 - 840188
rob-222 - 394383
kim-456 - 783099
may-111 - 840188
  • rand() 是生成随机数的函数,例如 0.840188
  • seen 是一个关联数组,键为$1,值为随机数
  • !seen[$1] - 对不在数组中的键执行此块seen
  • seen[$1] = rand() * 1000000 - 使用 key=$1value=rand() 填充数组
  • {print $0 " - " seen[$1]} - 打印当前行并为数组中的键 $1 存储随机值。

编辑:(感谢 JID)可以使用这个 awk 命令来避免数字重复:

awk '!seen[$0]{do{x=int(rand()*1000);seen[$0]=x}while(nums[x])} 
     {print $0, "-", seen[$0]}' ile
may-111 - 840
may-111 - 840
rob-222 - 394
kim-456 - 783
may-111 - 840

【讨论】:

  • 这可能会为不同的键生成两次相同的随机数。
  • 随机永远不是真正的随机,不是吗。对于可捕获的 # 个记录,它会起作用,但在大量记录后它可能会重复。
  • 另见 EDIT 部分了解替代方法。
  • 这里有一种没有重复随机数的rand方式awk '!a[$0]{do{x=int(rand()*1000);a[$0]=x}while(b[x])}{print $0,a[$0]}' file
  • 这个错误比它最初看起来更严重——它类似于生日问题。使用这组 1000000 个随机数,当请求 1178 个唯一标识符时,首先生成重复的机会超过 50%。这不是很多标识符,50% 在上下文中是一个非常的概率。
【解决方案2】:

您可以创建一个标识符,作为它第一次出现的行号:

$ awk '{if ($1 in a) {c=a[$1]} else {c=NR; a[$1]=c}} {print $1, c}' file
may-111 1
may-111 1
rob-222 3
kim-456 4
may-111 1

这样,您不会得到任何重复的值。

更惯用的(thanks to JID's suggestion):

awk '{!a[$0]&&a[$0]=NR}{print $0,a[$0]}' file

说明

这会将 id 存储在数组 a[] 中,这样每次我们读取一行时,我们都会交叉检查它是否已经定义了关联值。

  • {if (...) {action if true} else {action if false}
  • {if ($1 in a) {c=a[$1]} else {c=NR; a[$1]=c}} 从我们第一次读取该行时获取关联值。如果不是这种情况,请获取存储的值。
  • print $1, c 将内容连同标识符一起打印出来。

你当然可以调整它:

  • 例如,对于不同的输出分隔符,请使用 -v OFS=" - "
  • 对于更大的关联值,求和或乘以或其他任何常量。

【讨论】:

  • 我看到一条评论飞走了:(
  • 这有点短awk '{!a[$0]&&a[$0]=NR}{print $0,a[$0]}' file。另一个评论也是我的,但它是错误的:)
  • @JID 感谢您的建议,它更加地道,我喜欢它。征得您的许可,我将其添加到我当前的解决方案中。非常感谢!
  • 没问题,很高兴你喜欢 :)
猜你喜欢
  • 1970-01-01
  • 2011-07-24
  • 1970-01-01
  • 2011-05-21
  • 1970-01-01
  • 2017-04-06
  • 1970-01-01
  • 1970-01-01
  • 2012-04-14
相关资源
最近更新 更多