digitalmars.D.learn - Sellecting randomly from a range
- Jesse Phillips (21/21) May 17 2009 This is more a tutorial which I'll put up on a wiki, but one question I ...
- bearophile (48/68) May 18 2009 It's essential to compare such code with other ways/languages to produce...
- Jesse Phillips (4/52) May 18 2009 Actually I've some unneeded code, there was no need for using take.
This is more a tutorial which I'll put up on a wiki, but one question I have is
why can't 0..8 work in a randomCover, and wouldn't it be nice to use regex for
creating a range ("[A-Z]" being all uppercase letters)?
Selecting randomly from a collection of elements is common and usually entails
selecting random numbers and making sure they haven't been used before. D2 has
several templated functions that when put together make this very easy.
The first thing to look at comes from std.random, randomCover(range, rnd). This
takes the range of items and creates a new range that is a random
representation of the elements.
Then found in std.range is take(count, range). This will give us the count
items from our range giving us yet another range. From here we are able to use
a foreach loop to grab each item, but what if we want to store this someplace
for latter use?
This brings us to std.algorithms where we find fill(range1, range2). It is
important to note that D arrays can be use as a range.
If we combine this with D's array slices you are able to fill the results from
two ranges. The code below is an example using all of this and selecting a
random number of elements from each list.
(If this ends up being poorly formatted I apologize
http://paste.dprogramming.com/dpi1a1wn )
import std.algorithm;
import std.random;
import std.range;
import std.stdio;
string[] list = ["one", "two", "three", "four", "five"];
string[] list2 = ["1", "2", "3", "4", "5"];
void main(string[] args) {
auto rnd = new Random(unpredictableSeed);
int count = uniform(1, list.length, rnd);
string[] result = new string[count*2];
fill(result[0..count], take(count, randomCover(list, rnd)));
fill(result[count..$], take(count, randomCover(list2, rnd)));
writeln(result);
}
May 17 2009
Jesse Phillips:
import std.algorithm;
import std.random;
import std.range;
import std.stdio;
string[] list = ["one", "two", "three", "four", "five"];
string[] list2 = ["1", "2", "3", "4", "5"];
void main(string[] args) {
auto rnd = new Random(unpredictableSeed);
int count = uniform(1, list.length, rnd);
string[] result = new string[count*2];
fill(result[0..count], take(count, randomCover(list, rnd)));
fill(result[count..$], take(count, randomCover(list2, rnd)));
writeln(result);
}
It's essential to compare such code with other ways/languages to produce a
similar output:
Something similar in Python:
from random import randint, choice
list1 = ["one", "two", "three", "four", "five"]
list2 = ["1", "2", "3", "4", "5"]
count = randint(1, len(list1))
result = [choice(list1) for _ in xrange(count)]
result.extend(choice(list2) for _ in xrange(count))
print result
In D1 with my dlibs:
import d.string: putr;
import d.random: choice, randInt;
import d.func: table;
void main() {
string[] list1 = ["one", "two", "three", "four", "five"];
string[] list2 = ["1", "2", "3", "4", "5"];
int count = randInt(1, list1.length);
auto result = table(choice(list1), count) ~
table(choice(list2), count);
putr(result);
}
There are ways to do something similar without array concat too, and to create
a lazy result too:
import d.string: putr;
import d.random: choice, randInt;
import d.func: xmap, array, xrange;
void main() {
string[] list1 = ["one", "two", "three", "four", "five"];
string[] list2 = ["1", "2", "3", "4", "5"];
int count = randInt(1, list1.length);
auto result = xmap((int i){return choice(i < count ? list1 : list2);},
xrange(count*2));
putr(array(result));
}
Or just:
import d.string: putr;
import d.random: choice, randInt;
import d.func: xmap, array, xrange;
void main() {
string[] list1 = ["one", "two", "three", "four", "five"];
string[] list2 = ["1", "2", "3", "4", "5"];
int count = randInt(1, list1.length);
auto result = xmap((int i){return choice(list1);}, xrange(count)) ~
xmap((int i){return choice(list2);}, xrange(count));
putr(array(result));
}
I'm waiting for lazy/eager array comps still in D.
Bye,
bearophile
May 18 2009
On Sun, 17 May 2009 18:08:26 -0400, Jesse Phillips wrote:
This is more a tutorial which I'll put up on a wiki, but one question I
have is why can't 0..8 work in a randomCover, and wouldn't it be nice to
use regex for creating a range ("[A-Z]" being all uppercase letters)?
Selecting randomly from a collection of elements is common and usually
entails selecting random numbers and making sure they haven't been used
before. D2 has several templated functions that when put together make
this very easy.
The first thing to look at comes from std.random, randomCover(range,
rnd). This takes the range of items and creates a new range that is a
random representation of the elements.
Then found in std.range is take(count, range). This will give us the
count items from our range giving us yet another range. From here we are
able to use a foreach loop to grab each item, but what if we want to
store this someplace for latter use?
This brings us to std.algorithms where we find fill(range1, range2). It
is important to note that D arrays can be use as a range.
If we combine this with D's array slices you are able to fill the
results from two ranges. The code below is an example using all of this
and selecting a random number of elements from each list.
(If this ends up being poorly formatted I apologize
http://paste.dprogramming.com/dpi1a1wn )
import std.algorithm;
import std.random;
import std.range;
import std.stdio;
string[] list = ["one", "two", "three", "four", "five"]; string[] list2
= ["1", "2", "3", "4", "5"];
void main(string[] args) {
auto rnd = new Random(unpredictableSeed);
int count = uniform(1, list.length, rnd);
string[] result = new string[count*2];
fill(result[0..count], take(count, randomCover(list, rnd)));
fill(result[count..$], take(count, randomCover(list2, rnd)));
writeln(result);
}
Actually I've some unneeded code, there was no need for using take.
fill(result[0..count], randomCover(list, rnd));
fill(result[count..$], randomCover(list2, rnd));
May 18 2009









bearophile <bearophileHUGS lycos.com> 