2 つまたは 3 つの値を持つ変数のような配列を宣言し、実行中にそれらをランダムに取得するにはどうすればよいですか?
a := [1, 2, 5] -- sample sake
select random(a) -- returns random value
どこから始めればよいですか?
2 つまたは 3 つの値を持つ変数のような配列を宣言し、実行中にそれらをランダムに取得するにはどうすればよいですか?
a := [1, 2, 5] -- sample sake
select random(a) -- returns random value
どこから始めればよいですか?
CREATE FUNCTION random_pick()
RETURNS int AS
$func$
DECLARE
a int[] := '{[0:2]=1,2,5}'; -- sample sake
BEGIN
RETURN a[floor((random()*3))::int];
END
$func$ LANGUAGE plpgsql VOLATILE
random()
は値 x を返します0.0 <= x < 1.0
。3 を掛けると、floor()
それが得られます0
。1
または2
、同じ確率で得られます。これは、 で始まるデフォルトの配列インデックスに対して 1 ずつずれます1
。効率化のために、代わりに配列インデックスを宣言して開始し0
ます。
Erwin Brandstetter は、OP の質問に十分に答えました。ただし、より複雑な配列から要素をランダムに選択する方法を理解しようとしている他の人 (2 か月前の私のように) のために、彼の機能を拡張しました。
CREATE OR REPLACE FUNCTION random_pick( a anyarray, OUT x anyelement )
RETURNS anyelement AS
$func$
BEGIN
IF a = '{}' THEN
x := NULL::TEXT;
ELSE
WHILE x IS NULL LOOP
x := a[floor(array_lower(a, 1) + (random()*( array_upper(a, 1) - array_lower(a, 1)+1) ) )::int];
END LOOP;
END IF;
END
$func$ LANGUAGE plpgsql VOLATILE RETURNS NULL ON NULL INPUT;
いくつかの仮定:
これは整数配列だけでなく、あらゆるタイプの配列にも当てはまります
NULL データは無視します。NULL は、配列が空の場合、または NULL が挿入された場合にのみ返されます (他の非配列型の値はエラーを生成します)。
配列は通常のようにフォーマットする必要はありません - 配列インデックスはどこでも開始および終了でき、ギャップなどがあってもかまいません。
これは一次元配列用です
その他の注意事項:
最初のIF
ステートメントがないと、空の配列は無限ループにつながります
ループがないと、ギャップと NULL により、関数は NULL を返します。
array_lower
配列がゼロから始まることがわかっている場合は、両方の呼び出しを省略します
array_upper
インデックスにギャップがある場合は、代わりにarray_length
;が必要になります。ギャップがなければ同じです(どちらが速いかはわかりませんが、大きな違いはないはずです)
+1
2 番目以降はarray_lower
、他の値と同じ確率で配列内の最後の値を取得するのに役立ちます。それ以外の場合は、random()
の出力を正確に 1 にする必要がありますが、これは決して起こりません。
これはアーウィンのソリューションよりもかなり遅く、ニーズに対してやり過ぎになる可能性があります。実際には、ほとんどの人は 2 つの理想的なカクテルを混ぜ合わせます。