Select to view content in your preferred language

Arcade question

662
4
Jump to solution
05-09-2022 03:15 PM
Aнастасия88
Regular Contributor

Hello Everyone, I have a Arcade question. I am trying to set up a calculation rule that populate a value in a text type field based on a previous value.

For example, an original value is '1234567' and what I want to do is replace this value with the original value plus 1, i.e. '1234568'.

I tried a code below in the expression builder of the calculation rule but it does not work - a value returns but it is not the correct value.

 

 

'attributes': {
    'A_Id': Text(Number(feature.A_Id) + 1,'0000000')}

 

 

 Any tips are much appreciated!

 

Tags (1)
0 Kudos
1 Solution

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

Ah, so you're dealing with numbers too big for Arcade.

 

But is there any other better way to achieve this?

If you have a constant part in your ID that doesn't change, you could remove that, convert the rest to number (hopefully smaller than 16 digits) and increase, then concatenate back.

 

If the whole ID is a number, then you probably will have to split it up. This isn't super easy, though, because you have to take care of a few things:

  • if the last part is "9", you can't just change it to "10" and concatenate
    • wrong: "1239" + 1  -->  "12310".
    • right: "1239" + 1  -->  "1240"
  • if a part starts with "0", you will have to add that back in
    • wrong: "00123" + 1   -->  "124"
    • right: "00123" + 1  -->  "00124"

 

I came up with this:

 

function increase (txt) {
    // split text into parts
    // part_length has to be smaller than 16
    var txt_length = Count(txt)
    var part_length = 15
    var parts = []
    for(var i = 0; i < txt_length; i += part_length) {
        Push(parts, Mid(txt, i, part_length))
    }
    for(var i = Count(parts) - 1; i >= 0; i -= 1) {
        // add 1 to the last element
        var old_part = parts[i]
        var new_part = Text(Number(old_part) + 1)
        parts[i] = new_part
        if(Count(new_part) < Count(old_part)) {
            // New_part is shorter (eg "000" -> "1")
            // add padding and break the loop
            var diff = Count(old_part) - Count(new_part)
            for(var j = 0; j < diff; j += 1) {
                parts[i] = "0" + parts[i]
            }
            break
        }
        if(Count(new_part) == Count(old_part) || i == 0) {
            // the part's length did not change or this is the first element
            // we're done, break the loop
            break
        }
        if(Count(new_part) > Count(old_part)) {
            // New_part is longer (eg "999" -> "1000")
            // remove the first digit and continue the loop
            parts[i] = Mid(new_part, 1, part_length)
            continue
        }
    }
    return Concatenate(parts)
}

 

 

This is pretty long, maybe it can be done in a simpler way...

 

 

function test(txt) {
    Console(txt +"\n" + increase(txt) + "\n")
}

test("00000")
test("98")
test("99")
test("1234567890123456789012345678901234567890")  // 40 digits!
test("9999999999999999999999999999999999999999")
test("10000000000000000000000000000000000000000")

 

00000
00001

98
99

99
100

1234567890123456789012345678901234567890
1234567890123456789012345678901234567891

9999999999999999999999999999999999999999
10000000000000000000000000000000000000000

10000000000000000000000000000000000000000
10000000000000000000000000000000000000001

 


Have a great day!
Johannes

View solution in original post

4 Replies
JohannesLindner
MVP Frequent Contributor

Hmmm, it seems to work:

JohannesLindner_0-1652160828315.png

 

Can you give an example of original values where it doesn't return the correct value?

Can you post the whole code, maybe your problem is in another part?


Have a great day!
Johannes
0 Kudos
Aнастасия88
Regular Contributor

Thanks for your reply!

I just realised that there is a threshold in digit number to convert string to number. 16 digits works but if it is more than that, it does not work.

Now I am thinking of split the text, convert them to number to update the value, and then concatenate them back to text. But is there any other better way to achieve this?

0 Kudos
JohannesLindner
MVP Frequent Contributor

Ah, so you're dealing with numbers too big for Arcade.

 

But is there any other better way to achieve this?

If you have a constant part in your ID that doesn't change, you could remove that, convert the rest to number (hopefully smaller than 16 digits) and increase, then concatenate back.

 

If the whole ID is a number, then you probably will have to split it up. This isn't super easy, though, because you have to take care of a few things:

  • if the last part is "9", you can't just change it to "10" and concatenate
    • wrong: "1239" + 1  -->  "12310".
    • right: "1239" + 1  -->  "1240"
  • if a part starts with "0", you will have to add that back in
    • wrong: "00123" + 1   -->  "124"
    • right: "00123" + 1  -->  "00124"

 

I came up with this:

 

function increase (txt) {
    // split text into parts
    // part_length has to be smaller than 16
    var txt_length = Count(txt)
    var part_length = 15
    var parts = []
    for(var i = 0; i < txt_length; i += part_length) {
        Push(parts, Mid(txt, i, part_length))
    }
    for(var i = Count(parts) - 1; i >= 0; i -= 1) {
        // add 1 to the last element
        var old_part = parts[i]
        var new_part = Text(Number(old_part) + 1)
        parts[i] = new_part
        if(Count(new_part) < Count(old_part)) {
            // New_part is shorter (eg "000" -> "1")
            // add padding and break the loop
            var diff = Count(old_part) - Count(new_part)
            for(var j = 0; j < diff; j += 1) {
                parts[i] = "0" + parts[i]
            }
            break
        }
        if(Count(new_part) == Count(old_part) || i == 0) {
            // the part's length did not change or this is the first element
            // we're done, break the loop
            break
        }
        if(Count(new_part) > Count(old_part)) {
            // New_part is longer (eg "999" -> "1000")
            // remove the first digit and continue the loop
            parts[i] = Mid(new_part, 1, part_length)
            continue
        }
    }
    return Concatenate(parts)
}

 

 

This is pretty long, maybe it can be done in a simpler way...

 

 

function test(txt) {
    Console(txt +"\n" + increase(txt) + "\n")
}

test("00000")
test("98")
test("99")
test("1234567890123456789012345678901234567890")  // 40 digits!
test("9999999999999999999999999999999999999999")
test("10000000000000000000000000000000000000000")

 

00000
00001

98
99

99
100

1234567890123456789012345678901234567890
1234567890123456789012345678901234567891

9999999999999999999999999999999999999999
10000000000000000000000000000000000000000

10000000000000000000000000000000000000000
10000000000000000000000000000000000000001

 


Have a great day!
Johannes
Aнастасия88
Regular Contributor

Thanks Johannes for your advice!

As you said, I would need to figure out the nature of the text value to make decision which way to go. Hopefully, there is a constant part of less than 16 digits. Also thanks a lot for giving the example of a code - this would help me a lot!

0 Kudos