【问题标题】:How can I generate a file of random negative and positive integers in serial?如何串行生成随机负整数和正整数文件?
【发布时间】:2010-10-18 03:02:30
【问题描述】:

我想要一个随机生成的正负序列整数文件。现在,我要求文件包含大致相等数量的负数和正数(无需保证),但以后可以轻松更改比例。 “串行”是指第k个随机负数等于-k,第k个随机正数等于+k。

这个 GNU Bash 脚本单行符可以满足文件格式,但不会是 random

$ seq -1 -1 -5 && seq 1 5
-1
-2
-3
-4
-5
1
2
3
4
5

这个例子更好地展示了我正在寻找的东西,但仍然不是随机的,因为整数可预测地在负数和正数之间交替。

$ paste <(seq -1 -1 -5) <(seq 1 5) | tr '\t' '\n'
-1
1
-2
2
-3
3
-4
4
-5
5

通过 shuf 命令发送其中一个会使它们随机为负或正,但它们会失去序列性。

$ paste <(seq -1 -1 -5) <(seq 1 5) | tr '\t' '\n' | shuf
-5
4
3
2
-2
1
-1
-4
5
-3

注意:我正在尝试测试排序列表/位数组(零和一)的算法,但如果我使用 0 和 1,我将无法分析排序的行为或判断是否保持稳定性。

【问题讨论】:

  • 你想要随机数还是随机排序的集合?
  • 我想要一个具有我所描述的品质的文件,我不在乎它是从什么生成的。
  • 问题是你的措辞不清楚。如果很清楚“[你]描述的品质”是什么,就没有必要问了。 :-P 问题在于您谈论的是“随机生成的数字”,但随机的只是数字来自哪个序列(正数或负数)。
  • 我尽我所能去描述它。这很难做到。我怎么能做得更好?我在哪里说“随机生成的数字”。错误引用我是一种糟糕的形式。
  • 好吧,我在第一条评论中为您介绍了两种可能性。你想要哪一款?

标签: language-agnostic bash random awk


【解决方案1】:

如果我理解正确,您希望将正整数和负整数随机交错。例如:1 2 -1 3 -2 4 5- 3

my $count = 10;
my $pos   =  1;
my $neg   = -1;

my @random = map { 
    int(rand 2) 
    ? $pos++ 
    : $neg--
} 1..$count; 

print "@random\n";

更新:

要改变比例,我会这样做:

use strict;
use warnings;

my $next = get_list_generator(.5);

my @random = map $next->(), 1..10; 
print "@random\n";

my $again = get_list_generator(.25);

my @another = map $again->(), 1..10; 
print "@another\n";

sub get_list_generator {
    my $prob_positive = shift;

    my $pos = 1;
    my $neg = -1;

    return sub {
        return rand() <= $prob_positive ? scalar $pos++ : scalar $neg--;
    }

}

get_list_generator() 函数返回一个闭包。这样,您甚至可以同时运行多个列表生成器。

【讨论】:

    【解决方案2】:

    让我们开始高尔夫比赛吧? (44)

    perl -le'print rand>.5?++$a:--$b for 1..10'
    

    编辑daotoad's 40 字符版本

    seq 1 10|perl -ple'$_=rand>.5?++$a:--$b'
    

    【讨论】:

    • 是的,越简洁越好。看起来改变比例会更容易。
    • 如果你想打高尔夫球,试试:seq 1 10|perl -pe '$_=rand>.5?++$a:--$b' (40 chars)
    • 以前从未见过 -l 选项。不知道我是怎么错过的。
    【解决方案3】:

    其中15 是生成的数字总量,tp 是您想要的正数数量(有效表示 pos/neg 的比率):

    tp=8
    unset p n
    for i in $(printf '%s\n' {1..15} | gsort -R); do
        (( i <= tp )) && \
            echo $((++p)) || \
            echo $((--n))
    done
    

    【讨论】:

    • (比 perl 短得多;那一定是历史里程碑)
    【解决方案4】:
    #!/bin/bash
    
    pos=0 neg=0
    for i in {1..10}
    do 
        if (( ($RANDOM > 16384 ? ++pos : --neg) > 0 ))
        then echo $pos
        else echo $neg
        fi
    done
    

    我无法将其完全放入单行中。还有其他人吗?

    编辑:啊,一个单行,65 个字符(如果你在同一个 shell 中重复调用,需要设置 a 和 b):

    a=0 b=0;for i in {1..10}; do echo $(($RANDOM>16384?++a:--b));done
    

    【讨论】:

    • Nitpick:你可以说“#!/bin/bash”而不是“In Bash:#!/bin/sh”。
    • $RANDOM > 16384 很可怕,但我明白了。 lhunath 的答案也因 Bash 缺乏浮点运算而苦苦挣扎。这就是为什么它被称为黑客攻击。
    • @ashawley 谢谢,bash 是正确的,我认为 POSIX sh 没有 $RANDOM。是的,这是一个丑陋的黑客;我最初是想把它放在一行中,所以它并不完全漂亮。
    【解决方案5】:

    这是受 lhunath 和 Brian 的回答启发的 Bash 单行(2?)。

    RANDOM=$$; pos=1; neg=-1; for i in {1..10}; do \
    echo $(( $(echo $RANDOM / 32767 \> 0.5 | bc -l) ? pos++ : neg-- )); done
    

    这是一个参加高尔夫比赛的 Awk 脚本 (44)。

    seq 1 10|awk '{print(rand()>0.5?++p:--n);}'
    

    这是更清晰的写法:

    seq 1 10 | awk 'BEGIN{srand(); pos=1; neg=-1;}
                    {print (rand() > 0.5 ? pos++ : neg--);}'
    

    【讨论】:

      【解决方案6】:

      没有一组数字可以满足您的所有标准。你不能说你想要随机但同时说第 k 个负值 == -k 和第 k 个正值 == k。你可以随机选择,也可以不随机。

      至于您要做什么,为什么不将这两个问题分开并在诸如长度为 n 的整数对数组之类的东西上测试排序。这对中的第一个可以是 0 或 1,第二个将是您的稳定性跟踪器(只是从 0 到 n 的计数)。

      生成您想要的 0 和 1 列表并将它们打乱,然后添加到跟踪器整数上。现在按它们的第一个元素对它们进行排序。

      排序的输入将如下所示。

      0, 1
      1, 2
      0, 3
      1, 4
      1, 5
      0, 6
      0, 7
      1, 8
      1, 9
      1, 10
      0, 11
      0, 12
      0, 13
      

      稳定的排序会产生这个

      0, 1
      0, 3
      0, 6
      0, 7
      0, 11
      0, 12
      0, 13
      1, 2
      1, 4
      1, 5
      1, 8
      1, 9
      1, 10
      

      不稳定的会产生 0 和 1,跟踪器整数乱序。

      【讨论】:

      • 也许我不清楚,但我认为您没有正确阅读。一个数是正数还是负数随机的,它的整数值不是。
      • 关于您为每个二进制“键”添加序列值的想法:是的,这就是我的意思。但是,我更喜欢使用正面和负面的 hack,因为它将算法的信息打包在一起——需要更改“什么是二进制”,但为了我的目的,需要跟踪的内容更少。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-06
      • 1970-01-01
      • 2018-10-09
      • 2014-08-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多