You can do this in (at least) two ways.
One is simply to have a vector with the cardinalities of your parameters. So since your parameter array is
[
[ 0, 1, -1 ],
[ 'hello', 'goodbye' ],
[ 0 .. 100 ],
]
the cardinalities are [ 3, 2, 101 ]. This gives 22101 = 404 combinations. Given any number from 0 to 403 inclusive, its remainder modulo 3 is the index of the parameter in the first option array, then modulo 2 again for the second, and modulo 101 for the third. E.g. 137:
137 modulo 3 is 2, so first parameter is -1. 137 integer-divided-by 3 is 45, 45 modulo 2 is 1, so parameter 2 is "goodbye". 45 idb 2 is 22, so third parameter is 22.
This allows for mapping the whole configuration to a single number and viceversa. Then you can have a function or method that will set the configuration from a number, given the arrays of possible values.
You can now just try all the values in sequence. This is just a brute force approach.
Another possibility is to assume that the performance function f(x, y, z) is reasonably continuous, i.e., the change in performances is proportional to the change of any given parameter from its i-th to i+j-th value; the more you change, the more performances will vary.
If this holds true, there are several options to find the performance maximum efficiently, without examining all the possible values. For example, you generate a number at random from 0 to (here) 403, thus obtaining an initial configuration (x, y, z). You can now increase or decrease any of the three parameters, which gives you at most twenty-seven sets of values to investigate (each parameter can increase by one, decrease by one or stay the same, which is three possibilities; and three are the parameters, so you raise the number of possibilities by the number of parameters and get 3^3 or 27). Run the performance test for each of these sets. The best combination will be your new starting point. Repeat (you will want to cache results for the last runs, since several sets would otherwise be examined repeatedly).
When you have many possible values for each parameter, this method allows for examining comparatively very few of them. If f() is "reasonably" well-behaved, this method will "walk" the parameter space following the line of steepest ascent, rapidly converging towards the best combination. You may want to use techniques such as annealing or restarting from a very different initial position to ensure that you do not get "stuck" in a local maximum.