ashawley
ashawley

Reputation: 4283

How can I generate a file of random negative and positive integers in serial?

I want a file of randomly generated positive or negative serial integers. For now, I ask the file contain roughly (no guarantee required) equal numbers of negative and positive, but make it easy to change the proportions later. By "serial", I mean the kth random negative is equal to -k, and the kth random positive is equal to +k.

This GNU Bash script one-liner would satisfy the file format, but just wouldn't be random.

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

This example shows what I'm looking for even better, but is still not random since the integers alternate predictably between negative and positive.

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

Sending one of these through the shuf command makes them randomly negative or positive, but they lose their serial-ness.

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

Note: I'm trying to test algorithms that sort lists/arrays of bits (zeros and ones), but if I use 0s and 1s I won't be able to analyse the sort's behaviour or tell if stability was preserved.

Upvotes: 1

Views: 2454

Answers (6)

Hynek -Pichi- Vychodil
Hynek -Pichi- Vychodil

Reputation: 26121

Let's start golf contest? (44)

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

Edit: daotoad's 40 chars version

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

Upvotes: 4

Brian Campbell
Brian Campbell

Reputation: 332886

#!/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

I could not quite fit this into a one-liner. Anyone else?

edit: Ah, a one liner, 65 characters (need to set a and b if you're repeatedly invoking this in the same shell):

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

Upvotes: 1

ashawley
ashawley

Reputation: 4283

Here's a Bash one-liner (2?) inspired by lhunath and Brian's answers.

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

Here's an Awk script that competes in the golf contest (44).

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

This is the clearer idiomatic way to write it:

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

Upvotes: 0

lhunath
lhunath

Reputation: 125406

Where 15 is the total amount of numbers generated and tp is the amount of positive numbers you want (effectively indicating the ratio of 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

Upvotes: 2

daotoad
daotoad

Reputation: 27183

If I understand correctly, you want to interleave the positive integers and the negative integers randomly. For example: 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";

Update:

To change proportions I'd do this:

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--;
    }

}

The get_list_generator() function returns a closure. This way you can even have multiple list generators going at once.

Upvotes: 6

There is no set of numbers that will fit all your criterion. You can't say you want random but at the same time say that the kth negative value == -k and the kth positive value == k. You can either have it random, or not.

As to what you're trying to do, why not separate the two concerns and test the sort on something like an array of pairs of integers length n. The first of the pair can be zero or 1 and the second of the pair will be your stability tracker (just a count from 0 to n).

Generate the list of 0's and 1's that you want and shuffle them then add on the tracker integer. Now sort the pairs by their first element.

The input to your sort will look something like this.

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

Stable sorts will produce this

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

Unstable ones will produce the 0's and 1's with the tracker integers out of order.

Upvotes: -1

Related Questions