array_length() of an empty array returning NULL - arrays

I'm developing some stored proceduces in PL/pgSQL and some of them are giving me some problems. The sprocs I'm developing receive by parameter an array which I use in a FOR LOOP to get all its elements. To define the upper bound of the FOR LOOP I use the array_length function.
FOR i IN 1..array_length(array,1) LOOP
--array[i] something in here
END LOOP;
The problems occurs when I give to the sprocs an empty array. Instead of not entering the cycle, the sproc simply returns an error, stating that the upper bound of the FOR LOOP is NULL. Shouldn’t it be 0?
Am I doing anything wrong with the FOR LOOP?
Is there any other way to use the same bounds in a LOOP without it returning NULL when using an empty array?
Note: I know I can always use a condition before the LOOP, like this:
IF array_length(array,1) IS NOT NULL THEN
but the problem is: This sproc is supposed to process thousands of calls in the shortest amount of time. As so, I'm not looking to something that adds an unnecessary overhead to the processing. I'm just looking if there is any way to “cycle” an empty array in a LOOP.

As always, if you want to have different behavior for NULL values, use the coalesce construct:
FOR i IN 1..coalesce(array_length(array, 1), 0) LOOP
RAISE NOTICE '%', array[i];
END LOOP;
As for the return value: array_length(x, N) returns the number of elements in Nth dimension. Since an empty array has no dimensions, it returns NULL. You're right that it's counterintuitive if you only consider simple arrays, but makes sense for multi-dimensional arrays.
Edit: Like Erwin Brandstetter wrote in the comments, it's more correct to use array_lower/upper to loop over array indices. These will work for arrays that are not 1-based. These also take a dimension argument and require coalesce:
FOR i IN coalesce(array_lower(array, 1), 1)..coalesce(array_upper(array, 1), 1) LOOP
RAISE NOTICE '%', array[i];
END LOOP;

Avoid the problem altogether by looping through the array with FOREACH, introduced with Postgres 9.1:
FOREACH i IN ARRAY $1
LOOP
-- do something
END LOOP;
Depending on what you want to do inside the loop, you might be able to avoid looping altogether and use plain SQL with unnest() instead. Set-based operations are typically faster than looping in PostgreSQL.
Example:
RETURN QUERY
SELECT elem || 'foo'
FROM unnest($1) AS t(elem);

Related

Is there a way to append several values to a Pine Script array in a single call?

I want to have a function within which several if conditions looking for specific integer values.
The function in some situations might be called several times in sequence in order to return the resulting values of several different if conditions.
The idea I had for this, in order to reduce the code's bulkiness, was to have the portion of the script executing the function as required run through an integer array whose each stored value is sent to the function.
But in order for this to reduce the amount of bulky code I need a way to add several values at once rather than having the values each added separately.
Is that possible in Pinescript? Or perhaps you have a different solution for executing such function?
To answer my own question, it seems a simple way to update an array to a set of new values is to use the built in function array.from.
var array<int> arr = array.new<int>(0, 0)
arr := array.from(1, 4, 10)
It doesn't even require clearing and appending the new values as it simply replaces the testArr array with the new input.
If one wants to append several additional values to an existing array rather than replacing all of the original values, it can be done like this:
arr := array.concat(arr, array.from(1, 4, 10))
If I understand your question correctly you would like a single mass update (addition) to array elements? No such function exists, each element must be individually updated, ideally in a loop if you have a consistent calculation.

Position of the lowest value greater than x in ordered postgresql array (optimization)

Looking at the postgres function array_position(anyarray, anyelement [, int])
My problem is similar, but I'm looking for the position of the first value in an array that is greater than an element. I'm running this on small arrays, but really large tables.
This works:
CREATE OR REPLACE FUNCTION arr_pos_min(anyarray,real)
RETURNS int LANGUAGE sql IMMUTABLE PARALLEL SAFE AS
'select array_position($1,(SELECT min(i) FROM unnest($1) i where i>$2))';
the array_position takes advantage of the fact that my array is ordered, but the second part doesn't. And I feel like the second part could potentially just return the position without having to re-query.
My arrays are only 100 elements long, but I have to run this millions of times and so looking for a performance pickup.
Suggestions appreciated.
This seems to be a bit faster
CREATE OR REPLACE FUNCTION arr_pos_min(p_input anyarray, p_to_check real)
RETURNS int
AS
$$
select t.idx
from unnest(p_input) with ordinality as t(i, idx)
where t.i > p_to_check
order by t.idx
limit 1
$$
LANGUAGE sql
IMMUTABLE
PARALLEL SAFE
;
The above will use the fact that the values in the array are already sorted. Sorting by the array index is therefor quite fast. I am not sure if unnest() is guaranteed in this context to return the elements in the order they are stored in the array. If that was the case, you could remove the order by and make it even faster.
I don't think that there is a more efficient solution than yours, except if you write a dedicated C function for that.
Storing large arrays is often a good recipe for bad performance.

eiffel: does the across structure move the cursor of current iterable structure?

I was wondering if the across structure uses an own cursor or a separated one? does it ensure that cursor hasn't moved and if so how can it be expressed for other examples?
ITERABLE uses so called external cursors, not internal ones merged with the underlying structure. As a result, iteration affects neither the structure nor any other cursor, created the same way. This is important to support nested or recursive iterations. For example, to find if there are duplicates, one can do the following:
across structure as i loop
across structure as j loop
if i.item = j.item then print ("Duplicates found.") end
end
end
Doing the same with internal cursors, like (note: the code is incorrect)
from structure.start until structure.after loop
x := structure.item
from structure.start until structure.after loop
if x = structure.item then print ("Duplicates found.") end
structure.forth
end
structure.forth
end
does not work, because the inner loop also changes the cursor of the outer loop.
The limitation of the cursors associated with ITERABLE is that the associated structure should not be changed during the whole course of iteration. This is not a theoretical limitation, but a practical one, to simplify implementation and to make it a bit more efficient.

How to check every single element of my array (in a loop)?

I am programming in Fortran and if all single elements of my array are positive I want to execute statement 1, if they are partly positive execute statement 2 and if all are negative execute statement 3.
I know I will probably need a 'do' loop and a 'if' construct but could not figure out how to do it best.
There is no need to use loop for a simple condition
if (ALL(A>0)) then
statement1
else if (ALL(A<0)) then
statement3
else
statement2
end if
Explanation: A>0 is an array of logical values based on evaluating the condition for each element of the original array A. Function ALL() then reduces this logical array and returns true if all elements are true and false otherwise.
You request a do loop in the title. If you really need to fix a particular error with that, you must show us the code from your efforts, your errors and all other important details.

What's the best way to delete elements from an object inside an iterator?

Suppose you want to delete an element from inside an iteration:
a = ['a','b','c','d','e'];
for i = 0 to len(a){
print a[i];
if (i==1) a.remove(i);
};
The output is a b d e, with c missing. This is a common bug that happens because you changed the array while it was still looping. Some workarounds include keeping a list of elements to delete after the loop, and updating the index after a deletion. How do you deal with this problem?
The most obvious approach is to iterate from the end of the array to the beginning:
a = ['a','b','c','d','e'];
for i = len(a)-1 downto 0 {
print a[i];
if (i==1) a.remove(i);
};
Many languages have iterators with support for deleting elements during forward iteration by telling the iterator to do the deletion. However, this does not always work (e.g., an iterator for the list returned by Java's Arrays.asList will not support deleting elements, because the list does not "own" the backing array.
If you have to forward iterate using an index, at least subtract 1 from the index when you delete the element. That way you won't skip elements.
It depends on whether your iterator access -- including the loop, which in your example iterates from 0 to 5, even though position 5 may no longer exist by the end -- is by concrete position in the collection, or by abstract reference to the next element.
For instance, iterators in Java are of the abstract type, so you can delete the pointed-to item and then reliably continue iterating through the remainder of them.
In a language like C, when iterating through an array you would more typically encounter the difficulty you describe and risk writing buggy code. Perhaps the best general solution is to accumulate the "to-delete" set of things which you want to delete, and then process them as a separate step. Only if you have full knowledge to the internal representation of the collection and how iteration works can you safely perform the deletion and then adjust the iterator -- and the termination condition of the loop -- correctly to continue iterating. This will, however, often by the case anyway if you are working with an array. It's just a question of whether the additional adjustment code is simpler than the code to maintain the "to-delete" set.
Your can delete it even inside an iteration via an iterator.
vector::iterator itVec = vectInt.begin();
for ( ; itVec != vectInt.end(); )
{
if (*itVec == 1022)
itVec = vectInt.erase(itVect);
else
++itVec;
}
the interator response to know the end of the elements (instead of via recording the length of the end), and free the memory.

Resources