Pass Multiple Sets or Arrays of Values to a Function

Pass multiple sets or arrays of values to a function

You can achieve that with a simple SQL function. Key feature is the function generate_subscripts():

CREATE OR REPLACE FUNCTION f_attendance(_arr2d int[])
RETURNS SETOF attendance AS
$func$
SELECT a.*
FROM generate_subscripts($1, 1) i
JOIN attendance a ON a.class = $1[i][1]
AND a.section = $1[i][2]

$func$ LANGUAGE ROWS 10 sql STABLE;

Call:

SELECT * FROM f_attendance(ARRAY[[1,1],[2,2]]);

Or the same with an array literal - which is more convenient in some contexts, especially with prepared statements:

SELECT * FROM f_attendance('{{1,1},{2,2}}');

The function always expects a 2D array. Even if you pass a single pair, nest it:

SELECT * FROM f_attendance('{{1,1}}');

Audit of your implementation

  1. You made the function VOLATILE, but it can be STABLE. Per documentation:

    Because of this snapshotting behavior, a function containing only SELECT commands can safely be marked STABLE.

    Related:

    • How to pass a parameter into a date function
  2. You also use LANGUAGE plpgsql instead of sql, which makes sense if you execute the function multiple times in the same session. But then you must also make it STABLE or you lose that potential performance benefit. The manual once more:

    STABLE and IMMUTABLE functions use a snapshot established as of the
    start of the calling query, whereas VOLATILE functions obtain a fresh
    snapshot at the start of each query they execute.

  3. Your EXPLAIN output shows an Index Only Scan, not a sequential scan like you suspect in your comment.

  4. There is also a sort step in your EXPLAIN output that does not match the code you show. Are you sure you copied the right EXPLAIN output? How did you obtain it anyway? PL/pgSQL functions are black boxes to EXPLAIN. Did you use auto_explain? Details:

    • Postgres query plan of a UDF invocation written in pgpsql
  5. The Postgres query planner has no idea how many array elements the passed parameter will have, so it is hard to plan the query and it may default to a sequential scan (depending on more factors). You can help by declaring the expected number of rows. If you typically don't have more than 10 items add ROWS 10 like I did now above. And test again.

How to pass multiple arguments including arrays to a function in Bash where order is not defined and array elements can have multiple words?

How can I solve the second example, where the order or parameter can vary?

There are two universal independent of programming language solutions to join a variadic length of a list of items together that any programmers should know about:

  1. Pass the count...

my_func() {
local tmp optionsa title text optionsb
tmp=$1
shift
while ((tmp--)); do
optionsa+=("$1")
shift
done
title="$1"
shift
tmp=$1
shift
while ((tmp--)); do
optionsb+=("$1")
shift
done
text=$1
my_command "${optionsa[@]}" "$title" "${optionsb[@]}" "$text"
}

my_func 0 "Title" 0 "Text"
my_func 0 "Title" "${#optionsb[@]}" "${optionsb[@]}" "Text"
my_func "${#optionsa[@]}" "${optionsa[@]}" "Title" "${#optionsb[@]}" "${optionsb[@]}" "Text"

  1. Use a sentinel value.

my_func() {
local tmp optionsa title text optionsb
while [[ -n "$1" ]]; do
optionsa+=("$1")
shift
done
title=$1
shift
while [[ -n "$1" ]]; do
optionsb+=("$1")
shift
done
text=$1
my_command "${optionsa[@]}" "$title" "${optionsb[@]}" "$text"
}
my_func "" "Title" "" "Text"
my_func "" "Title" "${optionsb[@]}" "" "Text"
my_func "${optionsa[@]}" "" "Title" "${optionsb[@]}" "" "Text"

And I see two bash specific solutions:


  1. Pass arrays as names and use namereferences.

my_func() {
# Use unique names to avoid nameclashes
declare -n _my_func_optionsa=$1
local title=$2
declare -n _my_func_optionsb=$3
local title=$4
my_command "${_my_func_optionsa[@]}" "$title" "${_my_func_optionsb[@]}" "$text"
}

# arrays have to exists
my_func optionsa "Title" optionsb "Text"

  1. Parse the arguments like a real man. This is actually universal solution, as it generally performs data serialization when creating list of arguments and then data deserialization when reading the arguments - the format (arguments as options) is specific to shell.

my_func() {
local args
# I am used to linux getopt, getopts would work as well
if ! args=$(getopt -n "$my_func" -o "a:t:b:x:" -- "$@"); then
echo "my_func: Invalid arguments" >&2
return 1
fi
set -- "$args"
local optionsa title optionsb text
while (($#)); do
case "$1" in
-a) optionsa+=("$2"); shift; ;;
-t) title="$2"; shift; ;;
-b) optionsb+=("$2"); shift; ;;
-x) text="$2"; shift; ;;
*) echo "my_func: Error parsing argument: $1" >&2; return 1; ;;
esac
shift
done
my_command "${optionsa[@]}" "$title" "${optionsb[@]}" "$text"
}

my_func -a opta1 -a opta2 -t Title -b optb1 -b optb2 -x text

# or build the options list from arrays:
# ie. perform data serialization
args=()
for i in "${optionsa[@]}"; do
args+=(-a "$i")
done
args+=(-t "title")
for i in "${optionsb[@]}"; do args+=(-b "$i"); done
args+=(-x "text")
my_func "${args[@]}"

Generally if a function has constant and small count of arguments, just use the arguments. If functions get complicated with more edge cases, I recommend to parse the arguments like a man - makes the function versatile and abstract, easy to expand and implement edge cases and handle corner cases and errors, easy to understand by other programmers, easily readable and parsable by human eyes.

Because your example codes may some problems, I recommend to research how does quoting work in shelll, specifically how "${array[@]}" differ from ${array[@]}, research how [@] differ from [*], how does and when word splitting expansion is performed and how it affects the parameters. All the unquoted array expansions in your code suffer from word splitting - the spaces will not be preserved, also in the first example.

pass multiple arrays and values into javascript function

You can use this function to get multiple selected options from select:

function get_selected_data(o){
var selectedOptions = [];
for (var i = 0; i < o.options.length; i++){
if(o.options[i].selected){
selectedOptions.push('"' + o.options[i].value + '"');
}
}
if(selectedOptions.length){
return '[]=[' + selectedOptions.join(',') + ']';
} else {
return '';
}
}

For example:

var queryString = "?fund" + get_selected_data(document.getElementById('fund'));
queryString += "&agent" + get_selected_data(document.getElementById('agent'));
queryString += "&fromDate=" + fromDate;
queryString += "&toDate=" + toDate;

c++ pass multiple data types (including arrays of different dimensions) to function

You could use constexpr-if:

#include <iostream>
#include <type_traits>

template <class D = double>
class Tensor {
public:
using content_dtype = D; // put it here for everyone to see

template <class T>
Tensor(const T& input) {
if constexpr (std::is_arithmetic_v<T>) {
if constexpr (std::is_integral_v<T>) {
if constexpr (std::is_unsigned_v<T>) {
std::cout << "arithmetic::itegral::unsigned\n";
} else {
std::cout << "arithmetic::itegral::signed\n";
}
} else {
std::cout << "arithmetic::floating_point\n";
}
} else if constexpr (std::is_array_v<T>) {
auto dim = std::extent_v<T>;
std::cout << "array with extent " << dim << '\n';
}
}
};

int main() {
unsigned a;
int b;
double c;
int d[10];

Tensor A{a};
Tensor B{b};
Tensor C{c};
Tensor D{d};
}

Output:

arithmetic::itegral::unsigned
arithmetic::itegral::signed
arithmetic::floating_point
array with extent 10

How to pass multiple function parameters in an array in php?

The values are empty, because with the foreach you are overwriting existing values.

You can even write it more simple and use array shorthand syntax with brackets for better readability.

The null coalesce operator is syntactic sugar to avoid writing isset() and also is ternary. If it is set, it will return its contents, otherwise set to an empty array.

new_action(['actions' => ['ACTION1', 'ACTION2'], 'tables' => ['table1', 'table2']]);

function new_action($p = array()): void {
$tables = $p['tables'] ?? [];
$actions = $p['actions'] ?? [];

var_dump($tables);
var_dump($actions);
}

array(2) { [0] => string(6) "table1" [1] => string(6) "table2" }

array(2) { [0] => string(7) "ACTION1" [1] => string(7) "ACTION2" }



Related Topics



Leave a reply



Submit