Hi @channel, with a FOR loop - I have the followin...
# cfml-general
g
Hi @channel, with a FOR loop - I have the following;
Copy code
for(myElement in myArray) {
...
}
Is there a way to determine the index? I have dumped "myElement" and just get the type and value. I am trying to create a condition within the loop where If the value = "0" - but only if it is the first element of the array
Copy code
for(myElement in myArray) {
    if(the value EQ 0 AND I myArray[0] {
    }
}
I can check before the loop with arrayFirst() But then I would need to create two loops for true/false cases. I can change the loop, too to use index / item / to / from... But I thought I would ask if there was someway to get the "metadata" - for interest just as much as a solution. As always - thanks!
z
the approach used in the bytecode for cfloop is a work in lucee is a piece of art performance wise
s
Hello @gavinbaumanis Here is my suggestion... count = 1; for( myElement in myArray ) { if( value EQ 0 AND count EQ 1 ) { .... } count = count + 1; } Declare one variable for count and increment the count inside the loop everytime. So you can check your condition based on the condition count EQ 1 which means the first loop or first index only. Hope it helps you, Thanks!
g
Hi @Sathya M, thanks for the reply. For the moment, I have done "pretty much" as you suggested.
Copy code
if(local.values.first() EQ "0") {
    local.p = 0;
} else {
    local.p = 1;
}

for(var local.v in local.values) {
	local.v = Trim(local.v);
	arrayAppend(local.a, local.p & "|" & local.v);
	local.p = local.p + 1;
}
I am still interested to know if there is a way to get the current index. Eg. for a query there is currentRow()
a
The position is passed into the callback
Looking at your example - I think you can get the same result using a
map
https://trycf.com/gist/6cf34647b1e3a14520668adbc63d7ff3/lucee5?theme=monokai
s
+1 to John's suggestions - not much cause to write for loops these days and .map() is a lot cleaner here. but if you do write a for loop, afaik in script there's not an automatic index counter made for you so you'd have to declare one
z
'cept performance 😉
s
how different is it?
b
myarray = ['orange','apple','banana'] arrayeach(myarray,function(element,index){ writeoutput(index) })
z
s
wow
a
interesting but... If you happen to iterating over 10,000,000 items and doing something then it's unlikely that the syntax you use will be the biggest time compared to what is actually happening in the loop, so I'd recommend readable code everytime 🙂
1
z
that's backwards, for a small loop who cares, for a large one it makes a differnce
a
I'm saying that the code that you run inside the loop will likely have way more impact on the performance than the actual syntax used to do the loop. So you could gain some performance by switching syntax, but I would suggest that whatever code inside the loop is where the bottleneck could be. I doubt many people are just doing
+1
inside loops 🙂
1
s
I think I just resist advising somebody to write code because of an engine inefficiency. like you're committing to technical debt by writing a syntax just because of LDEV-4473 if you have any reasonable expectation that Lucee will achieve parity with acf
which, this being the lucee channel, we all do
but if I had a million foobars to iterate over today, yeah, I'd write it to be efficient today
a
Yeah, so write readable code - then if you need to, optimise it if and when.
I've done it - turned readable code into horrible code just to gain performance - and it worked but, good grief was it painful to change the code later - heck yeah.
So for the original question in this thread - I'd recommend using
map
or
each
.
1
a
That said, isn't the task here not really tied to the index, but is tied to which iteration of the loop it is, where we care if it's the first or [any other]? Not sure the looping strategy is that relevant here?
Copy code
afterFirst = false
loop over the array
    if afterFirst // or !afterFirst
        do whatevs
    /if
    rest of processing
    afterFirst = true
/loop
Or could use
isFirst
and reverse the values, depending on what is more clear in the code, and has least negativity in its evaluation.
g
Thanks to everyone for their help / discussion. I have a UI that accepts a comma-separated list of values - that is used to create prompts for an IVR system. Below are two example rows - for two SEPARATE questions/prompts; 1,2,3,4,5 'Monday','Tuesday','Wednesday' These get stored in the database as a "~" separated list of key/value pairs; "1|1~2|2~3|3~4|4~5|5" "1|Monday~2|Tuesday~3|Wednesday", respectively. Where the "key" - is a key in a "struct" sense for the value - and ALSO the key you would press on your phone. So in the two examples above you would press "1" on your phone to register a response that is equal to "1" or "Monday" - for each of the two prompts. (In the UI) If you enter a list starting with a "0", (0,1,2,3) weird shit happens. What gets stored is; "1|0~2|1~3|2~4|3" The "Key" - is used to set the DTMF (phone key press) expected for the value of your answer. So you hear a prompt; "Using the scale 0-3 - tell us how awesome we are." But - the "key" assigned to a value of 0 is 1. You have to press "1" to answer "0". Similarly, you have to press "4" to answer "3". It's weird - and wrong. However, if I save the row into the database as; "0|0~1|1~2|2~3|3" Then the system correctly assigns a key-press of 0 with a value of 0 and a key-press of 3 with a value of 3. From the UI, prior to saving the data - the form input is stored in an array: So in the "save" function I need to determine if the very first item you gave me, in the UI - is a "0" - so that I can store that value of "0", with a key of "0", too. And if this is the case - then I need to save all subsequent values you gave me with a "key" that is the current index of the array minus one. If the very first value is NOT "0"; Just save the values you gave me, in the order you gave them to me, with a key starting at "1" - so a "simple" array loop works fine, here. With thanks again to everyone, and unless anyone sees "something" wrong with it, I am currently going with the following gist - which has three example entries 1..10 0..10 "Sun".."Sat" Which all work.
a
I'd definitely stick the logic in a function - you can then unit test it with all your example use cases 🙂 Does look like a use case for map to me though. https://trycf.com/gist/df7e34f6c3686021fdce0e39487e24e8/acf2021?theme=monokai
Looks like you just changed your gist, but think my advice still applies (although your logic is slightly different now - but hey that's why we have unit tests to check all scenarios! 😛 )
1
👍🏼 1
g
I'm not sure why .each() took my fancy, initially... possibly because I was already in a function and there is nowhere else in the code that comes close to ever needing this logic. tl;dr; - here is a new gist . I do like map(). No idea why it stuck with me - but - It was one of the first things I learned about the intersection of non-trivial math and software engineering / statistics. The discussion went something like... This math is just too crazy to understand - I don't even get the vocabulary. How I speak software engineering to a mathematician? How do I understand what a mathematician wants of my code?" Eng: "I need to run a function, the same function, for all items in the collection" Math: "Oh, we call that 'map' " Anyway - ongoing thanks for all the help / discussion.
s
I think I would just pass the starting number and get rid of the logic but, interesting idea, thanks for sharing!
g
@spills I see what you're saying - but this is unfortunately not a new piece of code and has multiple touchpoints in the platform. It would take over a week to make that change and update / create tests.
a
Pragmaticism should always win out. Improve the code yer working on right now. Don't make the code around it worse. Maybe extract the code yer working on into its own function if appropriate. As long as it's improving: it's a win.
👍🏼 1
3