Arraylen giving occasional miscount of elements - arrays

I am having a strange problem...I have set up a cfscript for use in creating a datatables JSON object, and occasionally I am receiving an unhandled exception error "the element at position X cannot be found" The X typically is one more than my array actually has, so in my case, i have 44 elements in an array, the expression error always states "position 45 cannot be found"
heres some code
/* 44 total items in this array*/
aColumns = ['nd_event_group_id','nd_event_id', 'pref_mail_name', 'request_status_code', "life_gift_pledge_ob_amt", 'activity', ... ];
/* this will return 44 */
iColumnsLen = ArrayLen(aColumns);
...
savecontent variable="rc.aaData" {
for (i=1; i <= rc.qResult.RecordCount ; i++) {
writeOutput('{');
for (col=1; col <= iColumnsLen; col++) {
// the next line is what is referenced by the expression error
// "The element at position 45 cannot be found"
writeOutput('"#aColumns[col]#":#SerializeJSON(rc.qResult[aColumns[col]][i])#');
writeOutput((col NEQ iColumnsLen) ? ',' : '');
}
writeOutput('}');
writeOutput((i NEQ rc.qResult.RecordCount ) ? ',' : '');
}
};
The strange part about this issue is that I cannot recreate the error with any precision, its a hit or miss thing that occasionally happens
this script is ran by a GET via AJAX
any ideas?

Deriving this from the comments posted, it sounds like you have variables unVARed. All function-local variables need to be declared as such, either with the VAR keyword, or by specifically scoping them in the LOCAL scope.
If you don't do this, variables are global to the CFC instance, and accordingly shared between functions. This sounds like your problem.
This is all in the docs: "CFC variables and scope".

Related

Typescript Array Push [duplicate]

I have the following code:
console.log("start");
for(var i = 0; i < array.length; i++){
console.log(i + " = " + array[i]);
}
console.log(array);
console.log("end");
This gives me the following output:
[16:34:41.171] start
[16:34:41.171] 0 = 0
[16:34:41.172] 1 = 168
[16:34:41.172] 2 = 171
[16:34:41.172] [0, 168, 171, 139]
[16:34:41.172] end
That is, it doesn't show the 139 element when iterating the array, but console.log does print it when outputting the whole array. WHY? (<-- the question)
I do modify the array later on, is the console.log somehow delayed until after I changed the array? Note tho that change the order of the statements, and putting consoel.log(array) directly at the start does not change the outcome (still different outputs).
I am using firefox 20.0
Update: If you want to see this behavior, copy and paste the code in the console and execute. Then close developer tools and open again, apparently the pointer thing only happens when the code is executed in the background(which happens when you reopen the console).
Console.log output of objects, is a pointer, no a real value. This means that if the object changes later, console.log object will be updated. Try:
console.log("start");
var array = [1];
for(var i = 0; i < array.length; i++){
console.log(i + " = " + array[i]);
}
console.log(array);
console.log("end");
array.push(9999);// you will see the 9999 in the console no matter it was added after the output.
To prevent pointer issues try this:
console.log(array.join()); because later in some point of your application you are adding the 139 value.

AutoHotKey - Declaring global array does not work

; Give user the opportunity to choose his own hotkey
Gui, Add, Hotkey, x21 y234 w240 h30 vPanicKey gRunPanicKey,^F12
global myList := ["foo"]
RunPanicKey:
if(PanicKey != "") { ; Make sure the hotkey chosen by the user isn't empty.
myList.Insert("bar") ; Insert new string into the array.
myList2 := myList[2] ; Get 2nd index value and store it in myList2
MsgBox,0,My Array, The 2nd value of myList is: %myList2%
}
return
It appears that myList.Insert() does not work here, because the script cannot find the array, therefore myList2 is empty. But how come? I thought I made the array global?
GuiClose:
ExitApp
return
global myList := ["foo"]
As seen from your comment, the problem lies not within the global keyword (which you actually do not need at all here). The reason your program is not working is that return statement. Everything after the first return in a script does not get executed automatically on script start. See https://autohotkey.com/docs/Scripts.htm#auto for details. So, simply move the variable initialization at the very beginning of your file.

Error while using removeChild() and accessing members of array

I am stuck doing this even though I know it's very simple. Yet, I am getting errors.
What I have:
I have 3 arrays.
1st Array contains objects of UpgradeButton class.
2nd Array contains objects of BuyButtonclass.
3rd Array named newCostlyShops contains Numbers.
BuyButton class and UpgradeButton class, both have a shopCode member which is a number; the number which I'm trying to equate.
What I'm trying to do:
My goal is to first look for BuyButton and UpgradeButton objects in the respective arrays which have shopCodes same as those in newCostlyShops.
After that, I removeChild() that object and splice it out from the array.
My Code:
Array 3:
var newCostlyShops:Array = new Array();
newCostlyShops = Object(root).WorkScreen_mc.returnCostlyShops();
trace(newCostlyShops); // this is tracing out the exact shopCodes I want and is working fine.
Deletion and Splicing codes:
for (looper = 0; looper < upgradeButtonsArray.length; looper++) {
for (var secondLooper: int = 0; secondLooper < newCostlyShops.length; secondLooper++) {
if (upgradeButtonsArray[looper].shopCode == newCostlyShops[secondLooper]) {
trace(looper);
trace(upgradeButtonsArray[looper]);
removeChild(upgradeButtonsArray[looper]);
upgradeButtonsArray.splice(looper, 1);
}
}
}
for (looper = 0; looper < buyButtonsArray.length; looper++) {
for (secondLooper = 0; secondLooper < newCostlyShops.length; secondLooper++) {
if (buyButtonsArray[looper].shopCode == newCostlyShops[secondLooper]) {
trace(looper);
trace(buyButtonsArray[looper]);
removeChild(buyButtonsArray[looper]);
buyButtonsArray.splice(looper, 1);
}
}
}
What's wrong with this Code:
I keep getting error
TypeError: Error #1010: A term is undefined and has no properties.
This error comes only after the 1st time this code is run and not the first time it is run. When I remove the removeChild and splice , this traces out objects that are not null, ever. Even after this whole function is called 100 times, the error is not shown. Only when I removeChild and use splice this occurs.
Is there something wrong with what I'm doing? How to avoid this error? This is throwing the whole program haywire. If there is any other alternative to this method, I'm open to take those methods as well as long as I don't get errors and my goal is reached.
It might sounds funny, but.... try to decrement looper after splicing.
trace(looper);
trace(upgradeButtonsArray[looper]);
removeChild(upgradeButtonsArray[looper]);
upgradeButtonsArray.splice(looper, 1);
looper--;
I think after splicing the array all item's are being shifted and you're skipping next one.
Also, you should get some more information with this error, like which class/line is throwing it. Maybe you need to enable "permit debugging" or something?
Bonus suggestion:
For newCostlyShops use Dictionary instead of Array so you won't have to nest for inside for...

AutoHotKey Adding to Array within function call

I know the newer version is better, but company does not allows me to. So the question is related to AutoHotKey, ver 1.0.47.06.
I am trying to refactor my 400 lines program, by separating them into functions.
CaseNumberArray := "" ; The array to store all the case numbers
CaseNumberArrayCount := 0
; Helper function to load the case number into the array
ReadInputFile() {
Loop, Read, U:\case.txt
{
global CaseNumberArrayCount
CaseNumberArrayCount += 1 ; Increment the ArrayCount
CaseNumberArray%CaseNumberArrayCount% := A_LoopReadLine
current := CaseNumberArray%CaseNumberArrayCount%
}
}
CreateOutputHeader()
ReadInputFile()
MsgBox, There are %CaseNumberArrayCount% case(s) in the file.
Loop, %CaseNumberArrayCount%
{
case_number := CaseNumberArray%A_Index%
MsgBox, %case_number%
}
The last part of the code is testing if I can retrieve the case numbers I loaded into the array named CaseNumberArray, but it is currently all blank.
I studied this question, the author user1944441 wrote:
Important: YourArray must not be global and the counter in
YourArray%counter% must not be global, the rest doesn't matter.
I experimented by placing the global variables in different location, but it still does not work. I know the CaseArrayCount is correctly stored, and the Read Loop is working as well (When it is outside of a function). Is it possible to separate the code into a function?
Usually, global/local declarations are placed right below the method header, not somewhere in some subsequent code block. After all, these declarations apply only to the entire function.
You have to distinguish between simple loop counter variables and variables holding the actual size of the array. In your code, CaseNumberArrayCount describes the size of CaseNumberArray whereas in the answer to which you're referring, it's a counter only used to iterate over the array, which might as well be local.
But you don't have to use two "variables" anyway. Your pseudo array (which can be accessed like CaseNumberArray1, CaseNumberArray2, CaseNumberArray2, ...) has an unused CaseNumberArray0, why not not store the size there?
A pseudo array is actually a collection of sequentially numbered variables. global CaseNumberArray (which by the way you didn't seem to try) will only allow access to the variable named CaseNumberArray, but not CaseNumberArray1 or CaseNumberArray2 and so on.
One solution would be to use Assume-global mode which makes every global variable accessible by default:
; Now, CaseNumberArray0 will hold the array length,
; rendering CaseNumberArrayCount unnecessary
CaseNumberArray0 := 0
; Helper function to load the case number into the array
ReadInputFile() {
; We want to access every global variable we have,
; beware of name conflicts within your function!
global
Loop, Read, test.txt
{
CaseNumberArray0 += 1
CaseNumberArray%CaseNumberArray0% := A_LoopReadLine
}
}
; Here's an alternative: Let AHK build the pseudo array!
ReadInputFileAlternative() {
global caseAlt0
FileRead, fileCont, test.txt
StringSplit, caseAlt, fileCont, `n, `r
}
ReadInputFile()
out := ""
Loop, %CaseNumberArray0%
{
out .= CaseNumberArray%A_Index% "`n"
}
MsgBox, There are %CaseNumberArray0% case(s) in the file:`n`n%out%
; Now, let's test the alternative!
ReadInputFileAlternative()
out := ""
Loop, %caseAlt0%
{
out .= caseAlt%A_Index% "`n"
}
MsgBox, There are %caseAlt0% case(s) in the alternative pseudo-array:`n`n%out%
Edit: "Real Arrays"
As suggested in the comments, here's what I would do instead: I would convince my boss to allow the use of an up-to-date version of AHK and then work with real arrays. This comes with several benefits:
Real arrays are fully managed by AHK, which means that things like inserting, removing, iterating and indexing can all automagically be done by AHK.
A real array resides in one real variable, meaning that you can pass it along functions and anywhere you want, without having to worry about the current scope and whether you can access it in the first place.
The array syntax is very similar to most other languages, making your code intuitive and easier to read. And maybe it helps you in the future when dealing with another language.
Primitive n-dimensional arrays (and primitive AHK objects in general) can be expressed using JSON. This provides you with an easy way to (de-)serialize AHK objects.
The following code snippet shows the two methods used above (reading loop and splitting), but with real arrays. You will notice that we don't need any global declarations anymore, since we now can declare the array inside our function, and simply pass it back to the caller. In my opinion, this is what functions should really look like: A "black box" that doesn't affect its surroundings.
; Method 1: Line by line
ReadLineByLine(file) {
out := []
Loop, Read, % file
{
out.Insert(A_LoopReadLine)
}
return out
}
; Method 2: StrSplit
ReadAndSplit(file) {
FileRead, fileCont, % file
return StrSplit(fileCont, "`n", "`r")
}
caseNumbers := ReadLineByLine("test.txt")
out := "ReadLineByLine() yields " caseNumbers.MaxIndex() " entries:`n`n"
; using the for loop
for idx, caseNumber in caseNumbers
{
out .= caseNumber "`n"
}
MsgBox % out
caseNumbers := ReadAndSplit("test.txt")
out := "ReadAndSplit() yields " caseNumbers.MaxIndex() " entries:`n`n"
; using the normal loop
Loop % caseNumbers.MaxIndex()
{
out .= caseNumbers[A_Index] "`n"
}
MsgBox % out
MsgBox % "The second item is " caseNumbers[2]

Clearing my array leaves blank array positions

So I'm facing a problem with an AS3 class that's not operating the way I need it to. It's a simple problem, but a complex set of methods that cause it.
Firstly, the 'quiz' I'm building has 6 questions loaded as external SWFs inside of a Shell, run by a class. First we declared a var "a_quiz" to hold 6 values pushed from the external SWFs. These 6 values are reduced to a string and then checked against another array that contains the correct answers. The following loadQuiz function is designed to launch one of three random quizes and clear the a_quiz array so it can take new answers:
public function loadQuiz():void {
a_quiz.length=0;
trace("loadQuiz");
n_quizCorrect = n_quizScore = 0;
n_currentQuiz = Math.floor(Math.random() * (n_totalTopics - n_quizStart + 1) + n_quizStart);
loadTopic(n_currentQuiz);
}
Now I've tested the Shell and confirmed that the trace "loadQuiz" fires every time. And the first time you load the quiz, everything behaves as it should. The 6 questions trace correct or incorrect responses and push 6 binary values into the a_quiz array. The output looks like this:
loadQuiz
incorrect
correct
incorrect
incorrect
incorrect
incorrect
0,1,0,0,0,0
you failed
Then I jump back to the main menu and launch again. This deploys the loadQuiz function all over again. The first line of the function:
a_quiz.length=0;
should be emptying the a_quiz array to accept new answers to mark against. But when I complete the quiz I get this:
loadQuiz
correct
correct
correct
correct
correct
correct
,,,,,,1,1,1,1,1,1
you failed
For some reason beyond my understanding, the push values are stacking on top of empty positions, so when the strings compare...they won't match. What is going on here?
The push function:
function handleClick(evt:MouseEvent):void{
var tempCORRECT = a_answerSheet.toString();
var tempSELECTION = a_selected.toString();
//
if(tempSELECTION == tempCORRECT){
trace('correct');
parentObj1.a_quiz[ parentObj1.n_currentQuestion - 1 ] = 1;
}else{
trace('incorrect');
parentObj1.a_quiz[ parentObj1.n_currentQuestion - 1 ] = 0;
}
parentObj1.n_currentQuestion ++;
// GOTO NEXT SLIDE
parentObj1.LOADNEXT('up');
}
The problem originated in the loading of the Quiz itself.
as you can see on the handleClick function:
parentObj.n_currentQuestion++
was increasing an integer variable on the parentObj's timeline called n_currentQuestion. The problem then, originated in how the quiz was logging n_currentQuestion when the quiz loads with this function:
public function loadQuiz():void {
a_quiz= [];
trace("loadQuiz");
n_quizCorrect = n_quizScore = 0;
n_currentQuiz = Math.floor(Math.random() * (n_totalTopics - n_quizStart + 1) + n_quizStart);
loadTopic(n_currentQuiz);
}
So to correct the error, I needed to add a line to the loadQuiz, so that it would always load with n_currentQuestion set to 1.
public function loadQuiz():void {
a_quiz= [];
n_currentQuestion = 1;
trace("loadQuiz");
n_quizCorrect = n_quizScore = 0;
n_currentQuiz = Math.floor(Math.random() * (n_totalTopics - n_quizStart + 1) + n_quizStart);
loadTopic(n_currentQuiz);
}

Resources