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!
Solved! Go to Solution.
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:
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
Hmmm, it seems to work:
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?
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?
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:
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
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!