=> CREATE FUNCTION map(a INOUT float[], func text) AS $$ DECLARE i integer; x float; BEGIN IF cardinality(a) > 0 THEN FOR i IN array_lower(a,1)..array_upper(a,1) LOOP EXECUTE 'SELECT '||func||'($1)' USING a[i] INTO x; a[i] := x; END LOOP; END IF; END; $$ IMMUTABLE LANGUAGE plpgsql;
CREATE FUNCTION
=> SELECT map(ARRAY[4.0,9.0,16.0],'sqrt');
map --------- {2,3,4} (1 row)
=> SELECT map(ARRAY[]::float[],'sqrt');
map ----- {} (1 row)
Другой вариант реализации с циклом FOREACH:
=> CREATE OR REPLACE FUNCTION map(a float[], func text) RETURNS float[] AS $$ DECLARE x float; b float[]; -- пустой массив BEGIN FOREACH x IN ARRAY a LOOP EXECUTE 'SELECT '||func||'($1)' USING x INTO x; b := b || x; END LOOP; RETURN b; END; $$ IMMUTABLE LANGUAGE plpgsql;
CREATE FUNCTION
=> SELECT map(ARRAY[4.0,9.0,16.0],'sqrt');
map --------- {2,3,4} (1 row)
=> SELECT map(ARRAY[]::float[],'sqrt');
map ----- (1 row)
=> CREATE FUNCTION reduce(a float[], func text) RETURNS float AS $$ DECLARE i integer; r float := NULL; BEGIN IF cardinality(a) > 0 THEN r := a[array_lower(a,1)]; FOR i IN array_lower(a,1)+1 .. array_upper(a,1) LOOP EXECUTE 'SELECT '||func||'($1,$2)' USING r, a[i] INTO r; END LOOP; END IF; RETURN r; END; $$ IMMUTABLE LANGUAGE plpgsql;
CREATE FUNCTION
=> SELECT reduce( ARRAY[1.0,3.0,2.0], 'greatest');
reduce -------- 3 (1 row)
=> SELECT reduce( ARRAY[1.0], 'greatest');
reduce -------- 1 (1 row)
=> SELECT reduce( ARRAY[]::float[], 'greatest');
reduce -------- (1 row)
Вариант с циклом FOREACH:
=> CREATE OR REPLACE FUNCTION reduce(a float[], func text) RETURNS float AS $$ DECLARE x float; r float; first boolean := true; BEGIN FOREACH x IN ARRAY a LOOP IF first THEN r := x; first := false; ELSE EXECUTE 'SELECT '||func||'($1,$2)' USING r, x INTO r; END IF; END LOOP; RETURN r; END; $$ IMMUTABLE LANGUAGE plpgsql;
CREATE FUNCTION
=> SELECT reduce( ARRAY[1.0,3.0,2.0], 'greatest');
reduce -------- 3 (1 row)
=> SELECT reduce( ARRAY[1.0], 'greatest');
reduce -------- 1 (1 row)
=> SELECT reduce( ARRAY[]::float[], 'greatest');
reduce -------- (1 row)
=> DROP FUNCTION map(float[],text);
DROP FUNCTION
=> CREATE FUNCTION map(a anyarray, func text, elem anyelement DEFAULT NULL) RETURNS anyarray AS $$ DECLARE x elem%TYPE; b a%TYPE; BEGIN FOREACH x IN ARRAY a LOOP EXECUTE 'SELECT '||func||'($1)' USING x INTO x; b := b || x; END LOOP; RETURN b; END; $$ IMMUTABLE LANGUAGE plpgsql;
CREATE FUNCTION
=> SELECT map(ARRAY[4.0,9.0,16.0],'sqrt');
map --------------------------------------------------------- {2.000000000000000,3.000000000000000,4.000000000000000} (1 row)
=> SELECT map(ARRAY[]::float[],'sqrt');
map ----- (1 row)
Пример вызова с другим типом данных:
=> SELECT map(ARRAY[' a ',' b','c '],'btrim');
map --------- {a,b,c} (1 row)
=> DROP FUNCTION reduce(float[],text);
DROP FUNCTION
=> CREATE FUNCTION reduce(a anyarray, func text, elem anyelement DEFAULT NULL) RETURNS anyelement AS $$ DECLARE x elem%TYPE; r elem%TYPE; first boolean := true; BEGIN FOREACH x IN ARRAY a LOOP IF first THEN r := x; first := false; ELSE EXECUTE 'SELECT '||func||'($1,$2)' USING r, x INTO r; END IF; END LOOP; RETURN r; END; $$ IMMUTABLE LANGUAGE plpgsql;
CREATE FUNCTION
=> CREATE FUNCTION add(x anyelement, y anyelement) RETURNS anyelement AS $$ BEGIN RETURN x + y; END; $$ IMMUTABLE LANGUAGE plpgsql;
CREATE FUNCTION
=> SELECT reduce( ARRAY[1,-2,4], 'add');
reduce -------- 3 (1 row)
=> SELECT reduce( ARRAY['a','b','c'],'concat');
reduce -------- abc (1 row)