Knuth's algorithm S: Difference between revisions

added RPL
No edit summary
(added RPL)
 
(37 intermediate revisions by 18 users not shown)
Line 2:
This is a method of randomly sampling n items from a set of M items, with equal probability; where M >= n and M, the number of items is unknown until the end.
This means that the equal probability sampling should be maintained for all successive items > n as they become available (although the content of successive samples can change).
 
 
;The algorithm:
#:* Select the first n items as the sample as they become available;
#:* For the i-th item where i > n, have a random chance of n/i of keeping it. If failing this chance, the sample remains the same. If not, have it randomly (1/n) replace one of the previously selected n items of the sample.
#:* Repeat #&nbsp; 2<sup>nd</sup> step &nbsp; for any subsequent items.
 
 
;The Task:
#:* Create a function <code>s_of_n_creator</code> that given <math>n</math> the maximum sample size, returns a function <code>s_of_n</code> that takes one parameter, <code>item</code>.
#:* Function <code>s_of_n</code> when called with successive items returns an equi-weighted random sample of up to n of its items so far, each time it is called, calculated using Knuths Algorithm S.
#:* Test your functions by printing and showing the frequency of occurrences of the selected digits from 100,000 repetitions of:
:::# Use the s_of_n_creator with n == 3 to generate an s_of_n.
:::# call s_of_n with each of the digits 0 to 9 in order, keeping the returned three digits of its random sampling from its last call with argument item=9.
 
 
Note: A class taking n and generating a callable instance/function might also be used.
 
 
;Reference:
* The Art of Computer Programming, Vol 2, 3.4.2 p.142
 
 
;Cf.
;Related tasks:
* [[One of n lines in a file]]
* [[Accumulator factory]]
<br><br>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">T S_of_n_creator
Int n
i = 0
[Int] sample
 
F (n)
.n = n
 
F ()(item)
.i++
I .i <= .n
.sample.append(item)
E I random:(.i) < .n
.sample[random:(.n)] = item
 
V binarr = [0] * 10
V items = Array(0..9)
print(‘Single run samples for n = 3:’)
V s_of_n = S_of_n_creator(3)
L(item) items
s_of_n(item)
print(‘ Item: #. -> sample: #.’.format(item, s_of_n.sample))
 
L 100000
s_of_n = S_of_n_creator(3)
L(item) items
s_of_n(item)
L(s) s_of_n.sample
binarr[s]++
print("\nTest item frequencies for 100000 runs:\n "(enumerate(binarr).map((i, x) -> ‘#.:#.’.format(i, x)).join("\n ")))</syntaxhighlight>
 
{{out}}
<pre>
Single run samples for n = 3:
Item: 0 -> sample: [0]
Item: 1 -> sample: [0, 1]
Item: 2 -> sample: [0, 1, 2]
Item: 3 -> sample: [3, 1, 2]
Item: 4 -> sample: [3, 1, 2]
Item: 5 -> sample: [3, 1, 2]
Item: 6 -> sample: [3, 6, 2]
Item: 7 -> sample: [3, 7, 2]
Item: 8 -> sample: [3, 7, 2]
Item: 9 -> sample: [3, 7, 2]
 
Test item frequencies for 100000 runs:
0:30229
1:30182
2:29981
3:30058
4:29749
5:29952
6:30102
7:29955
8:29917
9:29875
</pre>
 
=={{header|Ada}}==
Line 28 ⟶ 95:
Instead of defining a function S_of_N_Creator, we define a generic packgage with that name. The generic parameters are N (=Sample_Size) and the type of the items to be sampled:
 
<langsyntaxhighlight Adalang="ada">generic
Sample_Size: Positive;
type Item_Type is private;
Line 39 ⟶ 106:
function Result return Item_Array;
 
end S_Of_N_Creator;</langsyntaxhighlight>
 
Here is the implementation of that package:
 
<langsyntaxhighlight Adalang="ada">with Ada.Numerics.Float_Random, Ada.Numerics.Discrete_Random;
 
package body S_Of_N_Creator is
Line 80 ⟶ 147:
D_Rnd.Reset(D_Gen); -- at package instantiation, initialize rnd-generators
F_Rnd.Reset(F_Gen);
end S_Of_N_Creator;</langsyntaxhighlight>
 
The main program:
 
<langsyntaxhighlight Adalang="ada">with S_Of_N_Creator, Ada.Text_IO;
 
procedure Test_S_Of_N is
Line 117 ⟶ 184:
& Natural'Image(Result(Dig)) & "; ");
end loop;
end Test_S_Of_N;</langsyntaxhighlight>
 
A sample output:
Line 126 ⟶ 193:
{{works with|BBC BASIC for Windows}}
At each of the 100000 repetitions not only is a new function created but also new copies of its PRIVATE variables '''index%''' and '''samples%()'''. Creating such a large number of variables at run-time impacts adversely on execution speed and isn't to be recommended, other than to meet the artificial requirements of the task.
<langsyntaxhighlight lang="bbcbasic"> HIMEM = PAGE + 20000000
PRINT "Single run samples for n = 3:"
Line 179 ⟶ 246:
a$ += STR$(a%(i%)) + ", "
NEXT
= LEFT$(LEFT$(a$)) + "]"</langsyntaxhighlight>
'''Output:'''
<pre>
Line 208 ⟶ 275:
 
=={{header|C}}==
{{Output?}}
Instead of returning a closure we set the environment in a structure:
<langsyntaxhighlight lang="c">#include <stdlib.h>
#include <stdio.h>
#include <string.h>
Line 281 ⟶ 347:
puts("");
return 0;
}</langsyntaxhighlight>
 
Sample output:
<pre> 29980 29746 30111 30034 29922 29720 30222 30183 29995 30087</pre>
 
=={{header|C++}}==
{{works with|C++11}}
<langsyntaxhighlight lang="cpp">#include <iostream>
#include <functional>
#include <vector>
Line 320 ⟶ 389:
std::cout << x << std::endl;
return 0;
}</langsyntaxhighlight>
{{out}}
<pre>
Line 336 ⟶ 405:
 
Class-based version:
<langsyntaxhighlight lang="cpp">#include <iostream>
#include <vector>
#include <cstdlib>
Line 373 ⟶ 442:
std::cout << bin[i] << std::endl;
return 0;
}</langsyntaxhighlight>
 
=={{header|Clojure}}==
Line 379 ⟶ 448:
Here the accumulator state is the current sample and the number of items processed.
This function is then used in a ''reduce'' call with an initial state and a list of items.
<langsyntaxhighlight lang="clojure">(defn s-of-n-fn-creator [n]
(fn [[sample iprev] item]
(let [i (inc iprev)]
Line 398 ⟶ 467:
sort
println)
</syntaxhighlight>
</lang>
Sample output:
<syntaxhighlight lang="text">([0 29924] [1 30053] [2 30018] [3 29765] [4 29974] [5 30225] [6 30082] [7 29996] [8 30128] [9 29835])</langsyntaxhighlight>
 
If we really need a stateful (thread safe!) function for some reason, we can get it like this:
<langsyntaxhighlight lang="clojure">(defn s-of-n-creator [n]
(let [state (atom [[] 0])
s-of-n-fn (s-of-n-fn-creator n)]
(fn [item]
(first (swap! state s-of-n-fn item)))))</langsyntaxhighlight>
 
=={{header|CoffeeScript}}==
<langsyntaxhighlight lang="coffeescript">
s_of_n_creator = (n) ->
arr = []
Line 442 ⟶ 511:
for digit in range
console.log digit, counts[digit]
</syntaxhighlight>
</lang>
output
<syntaxhighlight lang="text">
> coffee knuth_sample.coffee
0 29899
Line 456 ⟶ 525:
8 29976
9 30255
</syntaxhighlight>
</lang>
 
 
=={{header|Common Lisp}}==
<langsyntaxhighlight lang="lisp">(defun s-n-creator (n)
(let ((sample (make-array n :initial-element nil))
(i 0))
Line 486 ⟶ 554:
 
(princ (algorithm-s))
</langsyntaxhighlight>output<syntaxhighlight lang="text">#(30026 30023 29754 30017 30267 29997 29932 29990 29965 30029)</langsyntaxhighlight>
 
=={{header|D}}==
<langsyntaxhighlight lang="d">import std.stdio, std.random;
 
auto sofN_creator(in int n) {
Line 518 ⟶ 586:
}
writefln("Item counts for %d runs:\n%s", nRuns, bin);
}</langsyntaxhighlight>
{{out}}
<pre>Item counts for 100000 runs:
Line 524 ⟶ 592:
 
===Faster Version===
<langsyntaxhighlight lang="d">import std.stdio, std.random, std.algorithm;
 
struct SOfN(size_t n) {
Line 553 ⟶ 621:
}
writefln("Item counts for %d runs:\n%s", nRuns, bin);
}</langsyntaxhighlight>
 
=={{header|Elena}}==
ELENA 36.2x :
<langsyntaxhighlight lang="elena">import system'dynamic.;
import extensions.;
import system'routines.;
import system'collections.;
 
extension algorithmOp
{
s_of_n()
[{
var counter := Integer new. Integer();
var n := self.;
^ ArrayList new; ArrayList().mixInto:(new
{
eval(i)
{
eval : icounter.append(1);
[
counter append:1.
if (self length < n)
[ self append:i ];
[
if(randomGenerator eval:counter < n)
[ self[randomGenerator eval:n] := i ].
].
^ self array
]
}.
]
}
 
if (weak self.Length < n)
program =
{
[
weak self.append(i)
var bin := Array new:10; populate(:n)( Integer new ).
0 till:10000 do(:trial) }
else
[
var s_of_n := 3 s_of_n. {
if(randomGenerator.nextInt(counter) < n)
{ weak self[randomGenerator.nextInt(n)] := i }
0 till:10 do(:n)
[ };
 
var sample := s_of_n eval:n.
^ weak self.Value
}
})
}
}
public program()
{
var bin := Array.allocate(10).populate::(n => new Integer());
for(int trial := 0; trial < 10000; trial += 1)
{
var s_of_n := 3.s_of_n();
for(int n := 0; n < 10; n += 1)
{
var sample := s_of_n.eval(n);
if (n == 9)
[{ sample .forEach::(:i) [{ bin[i] .append:(1) ]} ]}
]}
].};
console .printLine:(bin; readChar).readChar()
}</syntaxhighlight>
].</lang>
{{out}}
<pre>
3001,3052,3033,2973,2981,3060,3003,2975,2959,2963
3050,3029,3041,2931,3040,2952,2901,2984,3069,3003
</pre>
 
=={{header|Elixir}}==
<langsyntaxhighlight lang="elixir">
defmodule Knuth do
def s_of_n_creator(n), do: {n, 1, []}
Line 638 ⟶ 709:
 
IO.inspect results
</syntaxhighlight>
</lang>
Output:
<pre>%{1 => 30138, 2 => 29980, 3 => 29992, 4 => 29975, 5 => 30110, 6 => 29825,
7 => 29896, 8 => 30188, 9 => 29898, 10 => 29998}</pre>
 
=={{header|F_Sharp|F#}}==
<syntaxhighlight lang="fsharp">
let N=System.Random 23 //Nigel Galloway: August 7th., 2018
let s_of_n_creator i = fun g->Seq.fold(fun (n:_[]) g->if N.Next()%(g+1)>i-1 then n else n.[N.Next()%i]<-g;n) (Array.ofSeq (Seq.take i g)) (Seq.skip i g)
let s_of_n<'n> = s_of_n_creator 3
printfn "using an input array -> %A" (List.init 100000 (fun _->s_of_n [|0..9|]) |> Array.concat |> Array.countBy id |> Array.sort)
printfn "using an input list -> %A" (List.init 100000 (fun _->s_of_n [0..9]) |> Array.concat |> Array.countBy id |> Array.sort)
</syntaxhighlight>
{{out}}
<pre>
using an input array -> [|(0, 30162); (1, 30151); (2, 29894); (3, 29766); (4, 30117); (5, 29976); (6, 29916); (7, 29994); (8, 29890); (9, 30134)|]
using an input list -> [|(0, 29936); (1, 29973); (2, 29880); (3, 30160); (4, 30126); (5, 30123); (6, 30062); (7, 30053); (8, 29892); (9, 29795)|]
</pre>
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 681 ⟶ 766:
}
fmt.Println(freq)
}</langsyntaxhighlight>
Output:
<pre>
[30075 29955 30024 30095 30031 30018 29973 29642 30156 30031]
</pre>
 
=={{header|Haskell}}==
 
{{libheader|containers}}
{{libheader|MonadRandom}}
{{libheader|random}}
{{libheader|mtl}}
 
<syntaxhighlight lang="haskell">
import Control.Monad.Random
import Control.Monad.State
import qualified Data.Map as M
import System.Random
 
-- s_of_n_creator :: Int -> a -> RandT StdGen (State (Int, [a])) [a]
s_of_n_creator :: Int -> a -> StateT (Int, [a]) (Rand StdGen) [a]
s_of_n_creator n v = do
(i, vs) <- get
let i' = i + 1
if i' <= n
then do
let vs' = v : vs
put (i', vs')
pure vs'
else do
j <- getRandomR (1, i')
if j > n
then do
put (i', vs)
pure vs
else do
k <- getRandomR (0, n - 1)
let (f, (_ : b)) = splitAt k vs
vs' = v : f ++ b
put (i', vs')
pure vs'
 
sample :: Int -> Rand StdGen [Int]
sample n =
let s_of_n = s_of_n_creator n
in snd <$> execStateT (traverse s_of_n [0 .. 9 :: Int]) (0, [])
 
incEach :: (Ord a, Num b) => M.Map a b -> [a] -> M.Map a b
incEach m ks = foldl (\m' k -> M.insertWith (+) k 1 m') m ks
 
sampleInc :: Int -> M.Map Int Double -> Rand StdGen (M.Map Int Double)
sampleInc n m = do
s <- sample n
pure $ incEach m s
 
main :: IO ()
main = do
let counts = M.empty :: M.Map Int Double
n = 100000
gen <- getStdGen
counts <- evalRandIO $ foldM (\c _ -> sampleInc 3 c) M.empty [1 .. n]
print (fmap (/ n) counts)
</syntaxhighlight>
 
=={{header|Icon}} and {{header|Unicon}}==
Line 696 ⟶ 839:
not a function. In Unicon, the calling syntax for this
co-expression is indistinguishable from that of a function.
<langsyntaxhighlight lang="unicon">import Utils
 
procedure main(A)
Line 719 ⟶ 862:
}
}
end</langsyntaxhighlight>
and a sample run:
<pre>->kas
Line 738 ⟶ 881:
Note that this approach introduces heavy inefficiencies, to achieve information hiding.
 
<langsyntaxhighlight lang="j">s_of_n_creator=: 1 :0
ctx=: conew&'inefficient' m
s_of_n__ctx
Line 762 ⟶ 905:
end.
)
</syntaxhighlight>
</lang>
 
Explanation: <code>create</code> is the constructor for the class named <code>inefficient</code> and it initializes three properties: <code>N</code> (our initial value), <code>ITEMS</code> (an initially empty list) and <code>K</code> (a counter which is initially 0).
Line 772 ⟶ 915:
Required example:
 
<langsyntaxhighlight lang="j">run=:3 :0
nl=. conl 1
s3_of_n=. 3 s_of_n_creator
Line 790 ⟶ 933:
7 36416
8 33172
9 29868</langsyntaxhighlight>
 
Here, we have each of our digits along with how many times each appeared in a result from <code>run</code>.
Line 808 ⟶ 951:
=={{header|Java}}==
A class-based solution:
<langsyntaxhighlight lang="java">import java.util.*;
 
class SOfN<T> {
private static final Random rand = new Random();
 
private List<T> sample;
private int i = 0;
private int n;
 
public SOfN(int _n) {
n = _n;
sample = new ArrayList<T>(n);
}
 
public List<T> process(T item) {
if (++i <= n) {
i++;
if (i <= n) {
sample.add(item);
} else if (rand.nextInt(i) < n) {
sample.set(rand.nextInt(n), item);
}
}
return sample;
}
}
 
public class AlgorithmS {
public static void main(String[] args) {
int[] bin = new int[10];
for (int trial = 0; trial < 100000; trial++) {
SOfN<Integer> s_of_n = new SOfN<Integer>(3);
for (int i = 0; i < 9; i++) s_of_n.process(i);
List<Integer> sample = null;
for (int s : s_of_n.process(9)) bin[s]++;
for (int i = 0; i < 10; i++)
}
sample = s_of_n.process(i);
System.out.println(Arrays.toString(bin));
for (int s : sample)
bin[s]++;
}
System.out.println(Arrays.toString(bin));
}
}</langsyntaxhighlight>
 
Sample output:
Output:
 
<pre>[3011529965, 3014129690, 3005029911, 2988729818, 2976530109, 3013230250, 2976730085, 3011429857, 3007930191, 2995030124]</pre>
 
Alternative solution without using an explicitly named type; instead using an anonymous class implementing a generic "function" interface:
<langsyntaxhighlight lang="java">import java.util.*;
 
interface Function<S, T> {
public T call(S x);
}
 
public class AlgorithmS {
private static final Random rand = new Random();
public static <T> Function<T, List<T>> s_of_n_creator(final int n) {
return new Function<T, List<T>>() {
private List<T> sample = new ArrayList<T>(n);
private int i = 0;
public List<T> call(T item) {
if (++i <= n) {
i++;
sample.add(item);
if (i <= n) {
} else if (rand.nextInt(i) < n) {
sample.add(item);
} else if sample.set(rand.nextInt(i) < n), {item);
}
sample.set(rand.nextInt(n), item);
return sample;
}
}
return sample;
};
};
}
 
public static void main(String[] args) {
int[] bin = new int[10];
for (int trial = 0; trial < 100000; trial++) {
Function<Integer, List<Integer>> s_of_n = s_of_n_creator(3);
for (int i = 0; i < 9; i++) s_of_n.call(i);
List<Integer> sample = null;
for (int i = 0; i < 10; ifor (int s : s_of_n.call(9)) bin[s]++);
}
sample = s_of_n.call(i);
System.out.println(Arrays.toString(bin));
for (int s : sample)
bin[s]++;
}
System.out.println(Arrays.toString(bin));
}
}</langsyntaxhighlight>
 
Sample output:
 
<pre>[29965, 30178, 29956, 29957, 30016, 30114, 29977, 29996, 29982, 29859]</pre>
 
=={{header|jq}}==
'''Adapted from [[#Wren]]'''
{{works with|jq}}
 
'''Also works with gojq, the Go implementation of jq'''.
 
jq does not support functions that return functions,
so we adopt the approach taken for example by the [[#C|C]] entry.
Specifically, following the [[#Wren|Wren]] model, the closure variables
are encapsulated in a JSON object of the form {n, s, next, m},
which is initially
<pre>
{n: $n, s: [range(0;$n)|0], next: 0, m: $n}
</pre>
where $n is the maximum sample size.
 
In the following, /dev/random is used as a source of entropy.
In a bash or bash-like environment, a suitable invocation would
be as follows:
<pre>
< /dev/random tr -cd '0-9' | fold -w 1 | jq -Mcnr algorithm-s.jq
</pre>
 
'''algorithm-s.jq'''
<syntaxhighlight lang=jq>
# Output: a PRN in range(0; .)
def prn:
if . == 1 then 0
else . as $n
| (($n-1)|tostring|length) as $w
| [limit($w; inputs)] | join("") | tonumber
| if . < $n then . else ($n | prn) end
end;
 
# Input and output: {n, s, next, m}
# The initial input should be
# {n: $n, s: [range(0;$n)|0], next: 0, m: $n}
# where $n is the maximum sample size.
def sOfN(items):
if (.next < .n)
then .s[.next] = items
| .next += 1
else .m += 1
| if ((.m | prn) < .n)
then (.n | prn) as $t
| .s[$t] = items
| if .next <= $t
then .next = $t + 1
else .
end
else .
end
end;
 
def task($iterations):
def dim($n): [range(0;$n)|0];
def init($n): {n: $n, s: dim($n), next: 0, m: $n };
 
reduce range(0; $iterations) as $r ( {freq: dim(10) };
reduce range(48; 57) as $d (. + init(3); sOfN($d) )
| reduce sOfN(57).s[] as $d (.;
.freq[$d - 48] += 1) )
| .freq ;
 
task(1e5)
</syntaxhighlight>
{{output}}
<pre>
[30008,29988,29827,30101,30308,30005,29808,29851,30218,29886]
</pre>
 
=={{header|Julia}}==
<syntaxhighlight lang="julia">using Printf
{{works with|Julia|0.6}}
 
<lang julia>function makesofn(n::Integer)
buf = Vector{typeof(n)}(0)
i = 0
Line 917 ⟶ 1,129:
for (i, c) in enumerate(nhist)
@printf("%5d → %5d\n", i-1, c)
end</langsyntaxhighlight>
 
{{out}}
Line 934 ⟶ 1,146:
=={{header|Kotlin}}==
{{trans|Java}}
Class based solution:
<lang scala>// version 1.1.2
<syntaxhighlight lang="scala">// version 1.2.51
 
import java.util.Random
 
val rand = Random()
 
class SOfN<T>(val n: Int) {
Line 942 ⟶ 1,157:
private var i = 0
 
privatefun companionprocess(item: objectT): List<T> {
val rand = Random()
}
 
fun process(item: T): ArrayList<T> {
if (++i <= n)
sample.add(item)
Line 954 ⟶ 1,165:
}
}
 
fun main(args: Array<String>) {
val bin = IntArray(10)
(1..100_000).forEach {
val sOfn = SOfN<Int>(3)
varfor sample:(d ArrayList<Int>?in =0..8) nullsOfn.process(d)
for (is in 0..9) sample = sOfn.process(i9)) bin[s]++
for (s in sample!!) bin[s]++
}
println(bin.contentToString())
}</langsyntaxhighlight>
Sample output:
{{out}}
<pre>
[3014429981, 2992829845, 3001229933, 2993830139, 3004030051, 3024430039, 3010729702, 2996930218, 2980230199, 2981629893]
</pre>
 
Alternative function based solution:
<syntaxhighlight lang="scala">// version 1.2.51
 
import java.util.Random
 
val rand = Random()
 
fun <T> SOfNCreator(n: Int): (T) -> List<T> {
val sample = ArrayList<T>(n)
var i = 0
return {
if (++i <= n)
sample.add(it)
else if (rand.nextInt(i) < n)
sample[rand.nextInt(n)] = it
sample
}
}
 
fun main(args: Array<String>) {
val bin = IntArray(10)
(1..100_000).forEach {
val sOfn = SOfNCreator<Int>(3)
for (d in 0..8) sOfn(d)
for (s in sOfn(9)) bin[s]++
}
println(bin.contentToString())
}</syntaxhighlight>
 
Sample output:
<pre>
[30172, 29856, 30132, 29884, 29818, 30220, 29900, 30069, 29869, 30080]
</pre>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">ClearAll[sofncreator]
sofncreator[n_] := Module[{sample, i},
sample = {};
i = 0;
Return[
Function[{item},
i++;
If[i <= n,
AppendTo[sample, item]
,
If[RandomInteger[{1, i}] <= n,
sample[[RandomInteger[{1, n}]]] = item
]
];
sample
]
]
]
bin = ConstantArray[0, 10];
items = Range[10];
sofn = sofncreator[3];
Do[
sample = sofn[item];
Print[" Item: ", item, " -> sample: " , sample]
,
{item, items}
]
Do[
sofn = sofncreator[3];
Do[
sample = sofn[item]
,
{item, items}
];
Do[
bin[[s]] += 1
,
{s, sample}
]
,
{trial, 100000}
];
{Range[Length[bin]], bin} // Transpose // Grid</syntaxhighlight>
{{out}}
<pre> Item: 1 -> sample: {1}
Item: 2 -> sample: {1,2}
Item: 3 -> sample: {1,2,3}
Item: 4 -> sample: {4,2,3}
Item: 5 -> sample: {5,2,3}
Item: 6 -> sample: {5,6,3}
Item: 7 -> sample: {7,6,3}
Item: 8 -> sample: {7,6,3}
Item: 9 -> sample: {7,6,3}
Item: 10 -> sample: {7,10,3}
 
1 29732
2 30055
3 30059
4 29787
5 30067
6 30123
7 30136
8 30056
9 29949
10 30036</pre>
 
=={{header|Nim}}==
 
<syntaxhighlight lang="nim">import random
 
func sOfNCreator[T](n: Positive): proc(item: T): seq[T] =
var sample = newSeqOfCap[T](n)
var i = 0
 
result = proc(item: T): seq[T] =
inc i
if i <= n:
sample.add(item)
elif rand(1..i) <= n:
sample[rand(n - 1)] = item
sample
 
when isMainModule:
 
randomize()
 
echo "Digits counts for 100_000 runs:"
var hist: array[10, Natural]
for _ in 1..100_000:
let sOfN = sOfNCreator[Natural](3)
for i in 0..8:
discard sOfN(i)
for val in sOfN(9):
inc hist[val]
 
for n, count in hist:
echo n, ": ", count</syntaxhighlight>
 
{{out}}
<pre>Digits counts for 100_000 runs:
0: 30092
1: 29906
2: 29956
3: 29896
4: 30151
5: 30000
6: 30267
7: 29853
8: 30186
9: 29693</pre>
 
=={{header|Objective-C}}==
{{works with|Mac OS X|10.6+}}
Uses blocks
<langsyntaxhighlight lang="objc">#import <Foundation/Foundation.h>
 
typedef NSArray *(^SOfN)(id);
Line 1,007 ⟶ 1,362:
}
return 0;
}</langsyntaxhighlight>
 
Log:
Line 1,017 ⟶ 1,372:
=={{header|OCaml}}==
 
<langsyntaxhighlight lang="ocaml">let s_of_n_creator n =
let i = ref 0
and sample = ref [| |] in
Line 1,031 ⟶ 1,386:
 
let () =
Random.self_init ();
let n = 3 in
let num_items = 10 in
let items_set = Array.init num_items (fun i -> i) in
let results = Array.createmake num_items 0 in
for i = 1 to 100_000 do
let res = test n items_set in
Line 1,041 ⟶ 1,396:
done;
Array.iter (Printf.printf " %d") results;
print_newline ()</langsyntaxhighlight>
 
Output:
Line 1,049 ⟶ 1,404:
=={{header|PARI/GP}}==
{{improve|PARI/GP|Does not return a function.}}
<langsyntaxhighlight lang="parigp">KnuthS(v,n)={
my(u=vector(n,i,i));
for(i=n+1,#v,
Line 1,063 ⟶ 1,418:
);
v
};</langsyntaxhighlight>
 
Output:
Line 1,069 ⟶ 1,424:
 
=={{header|Perl}}==
<langsyntaxhighlight lang="perl">use strict;
 
sub s_of_n_creator {
Line 1,103 ⟶ 1,458:
}
print "@bin\n";
</syntaxhighlight>
</lang>
 
;Sample output:
<pre>30003 29923 30192 30164 29994 29976 29935 29860 30040 29913</pre>
=={{header|Perl 6}}==
<lang perl6>sub s_of_n_creator($n) {
my @sample;
my $i = 0;
-> $item {
if ++$i <= $n {
push @sample, $item;
}
elsif $i.rand < $n {
@sample[$n.rand] = $item;
}
@sample;
}
}
 
=={{header|Phix}}==
my @items = 0..9;
{{trans|C}}
my @bin;
Phix does not support closures, but they are easy enough to emulate using {routine_id,environment}.<br>
 
Obviously the direct call (as commented out) is inevitably going to be marginally faster, and<br>
for ^100000 {
of course an s_of_n() that operated directly on local vars rather than elements of env, would be faster still.<br>
my &s_of_n = s_of_n_creator(3);
Not that a mere 100,000 samples takes any method more than a tiny fraction of a second, you understand.
my @sample;
<!--<syntaxhighlight lang="phix">(phixonline)-->
for @items -> $item {
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
@sample = s_of_n($item);
<span style="color: #008080;">enum</span> <span style="color: #000000;">RID</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">I</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">SAMPLE</span>
}
for @sample -> $s {
<span style="color: #008080;">function</span> <span style="color: #000000;">s_of_n</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">env</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">item</span><span style="color: #0000FF;">)</span>
@bin[$s]++;
<span style="color: #004080;">integer</span> <span style="color: #000000;">i</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">env</span><span style="color: #0000FF;">[</span><span style="color: #000000;">I</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
}
<span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">env</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SAMPLE</span><span style="color: #0000FF;">])</span>
}
<span style="color: #000000;">env</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">env</span><span style="color: #0000FF;">)</span>
say @bin;</lang>
<span style="color: #000000;">env</span><span style="color: #0000FF;">[</span><span style="color: #000000;">I</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span>
Output:
<span style="color: #008080;">if</span> <span style="color: #000000;">i</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">n</span> <span style="color: #008080;">then</span>
<pre>29975 30028 30246 30056 30004 29983 29836 29967 29924 29981</pre>
<span style="color: #000000;">env</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SAMPLE</span><span style="color: #0000FF;">][</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">item</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">/</span><span style="color: #000000;">i</span><span style="color: #0000FF;">></span><span style="color: #7060A8;">rnd</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">env</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SAMPLE</span><span style="color: #0000FF;">][</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">item</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">env</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">s_of_n_creator</span><span style="color: #0000FF;">(</span><span style="color: #004080;">int</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">s_of_n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">invoke</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">env</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">args</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">env</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">call_func</span><span style="color: #0000FF;">(</span><span style="color: #000000;">env</span><span style="color: #0000FF;">[</span><span style="color: #000000;">RID</span><span style="color: #0000FF;">],</span><span style="color: #7060A8;">prepend</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">args</span><span style="color: #0000FF;">),</span><span style="color: #000000;">env</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">env</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">items</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">env</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s_of_n_creator</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">items</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000080;font-style:italic;">-- env = s_of_n(env,items[i])</span>
<span style="color: #000000;">env</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">invoke</span><span style="color: #0000FF;">(</span><span style="color: #000000;">env</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">items</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">env</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SAMPLE</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">items_set</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">frequencies</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">items_set</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">100000</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">items_set</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">fdx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]+</span><span style="color: #000000;">1</span>
<span style="color: #000000;">frequencies</span><span style="color: #0000FF;">[</span><span style="color: #000000;">fdx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">frequencies</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
{29631,30097,29737,30252,29774,30147,29901,30042,30204,30215}
</pre>
Note that s_of_n_creator() must match {RID, I, SAMPLE}. You might instead prefer (taking the appropriate care not to miss any!):
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">enum</span> <span style="color: #000000;">RID</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">I</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">SAMPLE</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">CLOSURE_LEN</span><span style="color: #0000FF;">=$</span>
<span style="color: #0000FF;">...</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">s_of_n_creator</span><span style="color: #0000FF;">(</span><span style="color: #004080;">int</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">closure</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">CLOSURE_LEN</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">closure</span><span style="color: #0000FF;">[</span><span style="color: #000000;">RID</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">routine_id</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"s_of_n"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">closure</span><span style="color: #0000FF;">[</span><span style="color: #000000;">I</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">closure</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SAMPLE</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">closure</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<!--</syntaxhighlight>-->
 
=={{header|PHP}}==
{{works with|PHP|5.3+}}
<langsyntaxhighlight lang="php"><?php
function s_of_n_creator($n) {
$sample = array();
Line 1,168 ⟶ 1,564:
}
print_r($bin);
?></langsyntaxhighlight>
 
;Sample output:
Line 1,186 ⟶ 1,582:
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(de s_of_n_creator (@N)
(curry (@N (I . 0) (Res)) (Item)
(cond
Line 1,198 ⟶ 1,594:
(for I (mapc S_of_n (0 1 2 3 4 5 6 7 8 9))
(inc (nth Freq (inc I))) ) ) )
Freq )</langsyntaxhighlight>
Output:
<pre>-> (30003 29941 29918 30255 29848 29875 30056 29839 30174 30091)</pre>
Line 1,204 ⟶ 1,600:
=={{header|Python}}==
{{works with|Python|3.x}}
<langsyntaxhighlight lang="python">from random import randrange
 
def s_of_n_creator(n):
Line 1,237 ⟶ 1,633:
bin[s] += 1
print("\nTest item frequencies for 100000 runs:\n ",
'\n '.join("%i:%i" % x for x in enumerate(bin)))</langsyntaxhighlight>
 
;Sample output:
Line 1,266 ⟶ 1,662:
===Python Class based version===
Only a slight change creates the following class-based implementation:
<langsyntaxhighlight lang="python">class S_of_n_creator():
def __init__(self, n):
self.n = n
Line 1,281 ⟶ 1,677:
# Keep item
sample[randrange(n)] = item
return sample</langsyntaxhighlight>
The above can be instantiated as follows after which <code>s_of_n</code> can be called in the same way as it is in the first example where it is a function instead of an instance.
<langsyntaxhighlight lang="python">s_of_n = S_of_n_creator(3)</langsyntaxhighlight>
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">#lang racket/base
 
(define (s-of-n-creator n)
Line 1,306 ⟶ 1,702:
(for ([d sample]) (vector-set! counts d (add1 (vector-ref counts d)))))
 
(for ([d 10]) (printf "~a ~a\n" d (vector-ref counts d)))</langsyntaxhighlight>
Output:
<pre>0 30117
Line 1,318 ⟶ 1,714:
8 29940
9 29777</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line>sub s_of_n_creator($n) {
my (@sample, $i);
-> $item {
if ++$i <= $n { @sample.push: $item }
elsif $i.rand < $n { @sample[$n.rand] = $item }
@sample
}
}
 
my @bin;
for ^100000 {
my &s_of_n = s_of_n_creator 3;
sink .&s_of_n for ^9;
@bin[$_]++ for s_of_n 9;
}
 
say @bin;</syntaxhighlight>
Output:
<pre>29975 30028 30246 30056 30004 29983 29836 29967 29924 29981</pre>
 
=={{header|REXX}}==
<langsyntaxhighlight lang="rexx">/*REXX program using Knuth's algorithm S (a random sampling N of M items). */
parse arg trials size . /*obtain optional arguments from the CL*/
if trials=='' | trials=="," then trials=100000 100000 /*Not specified? Then use the default.*/
if size=='' | size=="," then size= 3 3 /* " " " " " " */
#.=0 0 /*initialize frequency counter array. */
do trials /*OK, now let's light this candle. */
call s_of_n_creator size /*create an initial list of N items. */
 
do genergen=0 for 10; call s_of_n gen /*call s_of_n with a single decimal dig*/
end /*gen*/
call s_of_n gener /*call s_of_n with a single decimal dig*/
end /*gener*/
 
/* [↓] examine what SofN generated. */
do count=1 for size; _= !.count /*get a dec. digit from the Nth item. */
#._= #._ + 1 /*bump counter for the decimal digit. */
end /*count*/
end /*trials*/
@= ' trials, and with a size of '
hdr= " Using Knuth's algorithm S for " commas(trials) @ || commas(size)": "
say hdr; say copies("═", length(hdr) ) /*display the header and its separator.*/
 
do dig=0 to 9 /* [↓] display the frequency of a dig.*/
say leftright('', 20) "frequency of the", 37) dig 'digit is: ' commas(#.dig)
end /*dig*/
exit /*stick a fork in it, we're all done. */
Line 1,348 ⟶ 1,764:
commas: parse arg _; do jc=length(_)-3 to 1 by -3; _=insert(',', _, jc); end; return _
/*──────────────────────────────────────────────────────────────────────────────────────*/
s_of_n: parse arg item; items=items + 1 items= items + 1 /*get "item", bump the items counter.*/
c=if random(1, items)>size then return /*probability [↓]isn't good, should replaceso askip previousit. item?*/
if_= random(1, c>size then return ); !._= item /*probabilitynow, isn'tfigure good,out which soprevious ··· skip it. */
_=random(1, size); !._=item /*now, figure out which previous ··· */
return /* ··· item to replace with ITEM.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
s_of_n_creator: parse arg item 1 items /*generate ITEM number of items. */
do k=1 for item /*traipse through the first N items. */
!.k= random(0, 9) /*set the Kth item with random digit.*/
end /*k*/
return return /*the piddly stuff is done (for now). */</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default input of: &nbsp; &nbsp; <tt> 100000 &nbsp; 2 </tt>}}
<pre>
Using Knuth's algorithm S for 100,000 trials, and with a size of 3:
═══════════════════════════════════════════════════════════════════════════
═════════════════════════════════════════════════════════════════════════
frequency of the 0 digit is: 29,670879
frequency of the 1 digit is: 2930,869259
frequency of the 2 digit is: 30,073254
frequency of the 3 digit is: 3029,076929
frequency of the 4 digit is: 2930,996022
frequency of the 5 digit is: 2930,914010
frequency of the 6 digit is: 3029,133692
frequency of the 7 digit is: 30,099108
frequency of the 8 digit is: 3029,036976
frequency of the 9 digit is: 3029,134871
</pre>
 
=={{header|RPL}}==
This is an idiomatic adaptation of the algorithm: SCREA initializes 2 persistent variables: S contains the sample and SPAR the algorithm parameters (n and i)
{{works with|RPL|HP49-C}}
« 0 2 →LIST '<span style="color:green">SPAR</span>' STO { } '<span style="color:green">S</span>' STO
» '<span style="color:blue">SCREA</span>' STO
« <span style="color:green">SPAR</span> EVAL
'''CASE'''
DUP2 > '''THEN''' DROP2 '<span style="color:green">S</span>' STO+ '''END'''
/ →NUM RAND ≥ '''THEN''' <span style="color:green">S</span> DUP SIZE RAND * CEIL ROT PUT '<span style="color:green">S</span>' STO '''END'''
DROP '''END'''
'<span style="color:green">SPAR</span>' 2 DUP2 GET 1 + PUT <span style="color:green">S</span>
» '<span style="color:blue">SOFN</span>' STO
« { } → sample
« { 10 } 0 CON
1 1000 '''START'''
3 <span style="color:blue">SCREA</span>
0
0 9 '''FOR''' k
DROP k <span style="color:blue">SOFN</span>
'''NEXT'''
'sample' STO
« sample k POS » 'k' 0 9 1 SEQ
NOT NOT AXL +
'''NEXT'''
» » '<span style="color:blue">TASK</span>' STO
{{out}}
<pre>
1: [ 206. 218. 235. 309. 359. 329. 327. 324. 359. 334. ]
</pre>
 
=={{header|Ruby}}==
Using a closure
<langsyntaxhighlight lang="ruby">def s_of_n_creator(n)
sample = []
i = 0
Line 1,399 ⟶ 1,846:
end
 
(0..9).each {|digit| puts "#{digit}\t#{frequency[digit]}"}</langsyntaxhighlight>
Example
<pre>0 29850
Line 1,411 ⟶ 1,858:
8 29953
9 29852</pre>
=={{header|Scala}}==
===Imperative (Ugly and side effects)===
<lang Scala>import java.util
import scala.util.Random
 
object KnuthsAlgorithmS extends App {
 
import scala.collection.JavaConverters._
 
val (n, rand, bin) = (3, Random, new Array[Int](10))
 
for (_ <- 0 until 100000) {
val sample = new util.ArrayList[Int](n)
for (item <- 0 until 10) {
if (item < n) sample.add(item)
else if (rand.nextInt(item + 1) < n)
sample.asScala(rand.nextInt(n)) = item
}
for (s <- sample.asScala.toList) bin(s) += 1
}
 
println(bin.mkString("[", ", ", "]"))
}</lang>
{{Out}}See it running in your browser by [https://scalafiddle.io/sf/nlldfXD/0 ScalaFiddle (JavaScript, non JVM)] or by [https://scastie.scala-lang.org/WLaee5H9T72cximqK9gECA Scastie (JVM)].
=={{header|Sidef}}==
{{trans|Perl 6}}
<lang ruby>func s_of_n_creator(n) {
var i = 0
var sample = []
{ |item|
if (++i <= n) {
sample << item;
}
elsif (i.rand < n) {
sample[n.rand] = item;
}
sample;
}
}
 
var items = 0..9;
var bin = [];
 
100000.times {
var s_of_n = s_of_n_creator(3);
var sample = []
for item in items {
sample = s_of_n(item);
}
for s in sample {
bin[s] := 0 ++;
}
}
 
say bin;</lang>
{{out}}
<pre>
[30056, 29906, 30058, 29986, 30062, 29748, 29989, 29985, 30126, 30084]
</pre>
 
=={{header|Rust}}==
Line 1,475 ⟶ 1,863:
{{libheader|rand 0.3}}
 
<langsyntaxhighlight lang="rust">use rand::{Rng,weak_rng};
 
struct SofN<R: Rng+Sized, T> {
Line 1,520 ⟶ 1,908:
println!("frequency of {}: {}", i, x);
}
}</langsyntaxhighlight>
 
{{out}}
Line 1,534 ⟶ 1,922:
frequency of 8: 30030
frequency of 9: 30003
</pre>
 
=={{header|Scala}}==
===Imperative (Ugly and side effects)===
{{trans|Java}}
<syntaxhighlight lang="scala">import java.util
import scala.util.Random
 
object KnuthsAlgorithmS extends App {
 
import scala.collection.JavaConverters._
 
val (n, rand, bin) = (3, Random, new Array[Int](10))
 
for (_ <- 0 until 100000) {
val sample = new util.ArrayList[Int](n)
for (item <- 0 until 10) {
if (item < n) sample.add(item)
else if (rand.nextInt(item + 1) < n)
sample.asScala(rand.nextInt(n)) = item
}
for (s <- sample.asScala.toList) bin(s) += 1
}
 
println(bin.mkString("[", ", ", "]"))
}</syntaxhighlight>
{{Out}}See it running in your browser by [https://scalafiddle.io/sf/nlldfXD/0 ScalaFiddle (JavaScript, non JVM)] or by [https://scastie.scala-lang.org/WLaee5H9T72cximqK9gECA Scastie (JVM)].
 
=={{header|Sidef}}==
{{trans|Raku}}
<syntaxhighlight lang="ruby">func s_of_n_creator(n) {
var i = 0
var sample = []
{ |item|
if (++i <= n) {
sample << item;
}
elsif (i.rand < n) {
sample[n.rand] = item;
}
sample;
}
}
 
var items = 0..9;
var bin = [];
 
100000.times {
var s_of_n = s_of_n_creator(3);
var sample = []
for item in items {
sample = s_of_n(item);
}
for s in sample {
bin[s] := 0 ++;
}
}
 
say bin;</syntaxhighlight>
{{out}}
<pre>
[30056, 29906, 30058, 29986, 30062, 29748, 29989, 29985, 30126, 30084]
</pre>
 
=={{header|Swift}}==
<langsyntaxhighlight lang="swift">import Darwin
 
func s_of_n_creator<T>(n: Int) -> T -> [T] {
Line 1,564 ⟶ 2,014:
}
}
println(bin)</langsyntaxhighlight>
{{out}}
<pre>
Line 1,571 ⟶ 2,021:
 
=={{header|Tcl}}==
<langsyntaxhighlight lang="tcl">package require Tcl 8.6
 
oo::class create SofN {
Line 1,599 ⟶ 2,049:
}
}
parray freq</langsyntaxhighlight>
Sample output:<pre>
freq(0) = 29812
Line 1,611 ⟶ 2,061:
freq(8) = 30060
freq(9) = 29824
</pre>
 
=={{header|V (Vlang)}}==
{{trans|go}}
<syntaxhighlight lang="v (vlang)">import rand
import rand.seed
fn s_of_ncreator(n int) fn(u8) []u8 {
mut s := []u8{len: 0, cap:n}
mut m := n
return fn[mut s, mut m, n](item u8) []u8 {
if s.len < n {
s << item
} else {
m++
if rand.intn(m) or {0} < n {
s[rand.intn(n) or {0}] = item
}
}
return s
}
}
fn main() {
rand.seed(seed.time_seed_array(2))
mut freq := [10]int{}
for _ in 0..int(1e5) {
s_of_n := s_of_ncreator(3)
for d := '0'[0]; d < '9'[0]; d++ {
s_of_n(d)
}
for d in s_of_n('9'[0]) {
freq[d-'0'[0]]++
}
}
println(freq)
}</syntaxhighlight>
Output:
<pre>
[30131, 30045, 29880, 30178, 29745, 29890, 30150, 30014, 30068, 29899]
</pre>
 
=={{header|Wren}}==
{{trans|Go}}
<syntaxhighlight lang="wren">import "random" for Random
 
var r = Random.new()
 
var sOfNCreator = Fn.new { |n|
var s = List.filled(n, 0)
var next = 0
var m = n
return Fn.new { |item|
if (next < n) {
s[next] = item
next = next + 1
} else {
m = m + 1
if (r.int(m) < n) {
var t = r.int(n)
s[t] = item
if (next <= t) next = t + 1
}
}
return s
}
}
 
var freq = List.filled(10, 0)
for (r in 0...1e5) {
var sOfN = sOfNCreator.call(3)
for (d in 48...57) sOfN.call(d)
for (d in sOfN.call(57)) {
freq[d - 48] = freq[d - 48] + 1
}
}
System.print(freq)</syntaxhighlight>
 
{{out}}
Sample run:
<pre>
[29842, 30051, 29878, 30178, 29731, 30089, 30070, 29939, 30058, 30164]
</pre>
 
=={{header|zkl}}==
<langsyntaxhighlight lang="zkl">fcn s_of_n_creator(n){
fcn(item,ri,N,samples){
i:=ri.inc(); // 1,2,3,4,...
Line 1,621 ⟶ 2,152:
samples
}.fp1(Ref(1),n,L())
}</langsyntaxhighlight>
One run:
<langsyntaxhighlight lang="zkl">s3:=s_of_n_creator(3);
[0..9].pump(List,s3,"copy").println();</langsyntaxhighlight>
{{out}}
<pre>
Line 1,630 ⟶ 2,161:
</pre>
100,000 runs:
<langsyntaxhighlight lang="zkl">dist:=L(0,0,0,0,0,0,0,0,0,0);
do(0d100_000){
(0).pump(10,Void,s_of_n_creator(3)).apply2('wrap(n){dist[n]=dist[n]+1})
}
N:=dist.sum();
dist.apply('wrap(n){"%.2f%%".fmt(n.toFloat()/N*100)}).println();</langsyntaxhighlight>
{{out}}
<pre>L("10.00%","9.98%","10.00%","9.99%","10.00%","9.98%","10.01%","10.04%","9.98%","10.02%")</pre>
1,150

edits