1

In a PineScript (v5), when I am trying to remove a duplicate using the following code snippet, getting a below error:

removeDuplicates(arrayData) =>
    copyArrayData = array.copy(arrayData)
    for i = 0 to (array.size(arrayData) == 0 ? na : array.size(arrayData) - 1)
        data = array.get(arrayData, i)
        for j = i to (array.size(arrayData) == 0 ? na : array.size(arrayData) - 1)
            if (data == array.get(arrayData, j))
                array.remove(copyArrayData, j)
    copyArrayData

My arrayData is just a price array of 5 elements.

The error:

In array.remove() function. Index 5 is out of bound, array size is 5.

Attached the photo.

My call of the function is like this:

    finalSupportArray := removeDuplicates(finalSupportArray)
    finalResistanceArray := removeDuplicates(finalResistanceArray)

enter image description here

Pradip
  • 509
  • 1
  • 5
  • 22

1 Answers1

2

array.remove will change your array's size and cause your for loop to work unpredictably. Because you are removing an element and changing the array's size while you are still in the loop.

When you need to remove something from an array, work with a temp array instead. So, create a dummy array, loop over the original array and only push the elements you want to have at the end to the temp array. Then return this temp array from your function.

Here is an example for you:

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © vitruvius

//@version=5
indicator("My script")

f_remove_duplicate(arr) =>
    temp_arr = array.new_int()
    len = array.size(arr)
    
    for i=0 to len-1
        val = array.get(arr, i)
        first_idx = array.indexof(arr, val)
        
        if (i == first_idx)  // Only one occurrence
            array.push(temp_arr, val)
    temp_arr

arr1 = array.from(1, 2, 3, 4, 5, 5, 5, 6, 7, 8, 6, 9, 1, 10)
arr2 = f_remove_duplicate(arr1)

len1 = array.size(arr1)
len2 = array.size(arr2)

var tbl = table.new(position = position.top_right, columns = 3, rows = len1 + 1, bgcolor = color.yellow, border_width = 1)

if barstate.islast
    row = 0
    
    table.cell(tbl, 0, row, "Idx")
    table.cell(tbl, 1, row, "Arr1")
    table.cell(tbl, 2, row, "Arr2")
    row := row + 1
    
    for i=0 to len1 - 1
        val1 = array.get(arr1, i)
        int val2 = (i < len2) ? array.get(arr2, i) : na
        
        table.cell(tbl, 0, row, str.tostring(i))
        table.cell(tbl, 1, row, str.tostring(val1))
        table.cell(tbl, 2, row, str.tostring(val2))
        row := row + 1

enter image description here

vitruvius
  • 15,740
  • 3
  • 16
  • 26
  • 1
    Great answer! Just one note, you probably meant last_idx = array.lastindexof(arr, val), right? I had tried to test this behaviour before and came to the conclusion that pine script is pretty good at handling the changed array size on the fly in a for loop... until it just fails for one element. Than it seems to work well again.. until the next one. It's a pity you need a workaround for this. – elod008 Oct 01 '22 at 18:39
  • 2
    @elod008, thanks for your comment. Actually, I meant to use `array.indexof` but I should rename my variable. I guess I tested with `array.lastindexof` and then switched to `array.indexof` but forgot to change the variable name. What I'm doing is checking if the current element is the first one in the array. If so, I push it to the temp array. – vitruvius Oct 01 '22 at 20:06
  • 2
    My mistake. You're absolutely right on that. I was on other thoughts... Good job! – elod008 Oct 01 '22 at 20:20
  • Thanks a lot. It worked like magic. I just, for safety, add a check of do-nothing if the 'arr' is of size 0. – Pradip Oct 02 '22 at 05:40