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