Breaking/Continuing nested for loops in Coffeescript - coffeescript

How can I break/continue nested loops in Coffeescript? E.g. I have something like:
for cat in categories
for job in jobs
if condition
do(this)
## Iterate to the next cat in the first loop
Also, is there a way to wrap the whole second loop as a conditional to another function within the first loop? E.g.
for cat in categories
if conditionTerm == job for job in jobs
do(this)
## Iterate to the next cat in the first loop
do(that) ## Execute upon eliminating all possibilities in the second for loop,
## but don't if the 'if conditionTerm' was met

break works just like js:
for cat in categories
for job in jobs
if condition
do this
break ## Iterate to the next cat in the first loop
Your second case is not very clear, but I assume you want this:
for cat in categories
for job in jobs
do this
condition = job is 'something'
do that unless condition

Use labels. Since CoffeeScript doesn't support them, you need to hack as such:
0 && dummy
`CAT: //`
for cat in categories
for job in jobs
if conditionTerm == job
do this
`continue CAT` ## Iterate to the next cat in the first loop
do that ## Execute upon eliminating all possibilities in the second for loop,
## but don't if the 'if conditionTerm' was met

Coffescript's "break" only breaks the immediate loop and has no way of identifying an outer loop for breakage (annoying!). This following hack works in some instances for breaking out of multiple loops when a condition is met:
ar1 = [1,2,3,4]
ar2 = [5,6,7,8]
for num1 in ar1
for num2 in ar2
console.log num1 + ' : ' + num2
if num2 == 6
breakLoop1 = true; break
break if breakLoop1
# Will print:
# 1 : 5
# 1 : 6

Using anonymous loop with return
do ->
for a in A
for b in B
for c in C
for d in D
for e in E
for f in F
for g in G
for h in H
for i in I
#DO SOMETHING
if (condition)
return true

Coffeescript would never have multiple breaking/continuing statements, you have to stick to ugly and excessive flags polluting your code or try to replace it by do with a lambda and use return as a multiple break.
https://github.com/jashkenas/coffeescript/issues/4254

For checking all elements in an array, maybe lodash's every would be of use?
https://lodash.com/docs#every
for cat in categories
if _.every jobs, conditionTerm
...

I suppose the design of your code is not very good if you want to use inner break/continue.
It seems to me that any programming language doesn`t allow that.
Using labels as someone suggested is also considered as bad style.

Related

SPSS/macro: split string into multiple variables

I am trying to split a string variable into multiple dummy coded variables. I used these sources to get an idea of how one would achieve this task in SPSS:
https://www.ibm.com/support/pages/making-multiple-string-variables-single-multiply-coded-field
https://www.spss-tutorials.com/spss-split-string-variable-into-separate-variables/
But when I try to adapt the first one to my needs or when I try to convert the second one to a macro, I fail.
In my dataset I have (multiple) variables that contain a comma seperated string that represents different combinations of selected items (as well as missing values). For each item of a specific variable I want to create a dummy variable. If the item was selected, it should be represented with a 1 in the new dummy variable. If it was not selected, that case should be represented with a 0.
Different input variables can contain different numbers of items.
For example:
ID
VAR1
VAR2
DMMY1_1
DMMY1_2
DMMY1_3
1
1, 2
8
1
1
0
2
1
1, 3
1
0
0
3
3, 1
2, 3, 1
1
0
1
4
2, 8
0
0
0
Here is what I came up with so far ...
* DEFINE DATA.
DATA LIST /ID 1 (F) VAR1 2-5 (A) VAR2 6-12 (A).
BEGIN DATA
11, 28
21 1, 3
33, 12, 3, 1
4 2, 8
END DATA.
* MACRO SYNTAX.
* DEFINE VARIABLES (in the long run these should/will be inside the macro function, but for now I will leave them outside).
NUMERIC v1 TO v3 (F1).
VECTOR v = v1 TO v3.
STRING #char (A1).
DEFINE split_var(vr = TOKENS(1)).
!DO !#pos=1 !TO char.length(!vr).
COMPUTE #char = char.substr(!vr, !#pos, 1).
!IF (!#char !NE "," !AND !#char !NE " ") !THEN
COMPUTE v(NUMBER(!#char, F1)) = 1.
!IFEND.
!DOEND.
!ENDDEFINE.
split_var vr=VAR1.
EXECUTE.
As I got more errors than I can count, it's hard to narrow down my problem. But I think the problem has something to do with the way I use the char.length() function (and I am a bit confused when to use the bang operator).
If anyone has some insights, I would really appreciate some help :)
There is a fundamental issue to understand about SPSS macro - the macro does not read or interact in any way with the data. All the macro does is manipulate text to write syntax. The syntax created will later work on the actual data when you run it.
So, for example, Your first error is using char.length(!vr) within the syntax. You are trying to get the macro to read the data, calculate the length and use, but that simply can't be done - the macro can only work with what you gave it.
Another example in your code: you calculate #char and then try to use it in the macro as !#char. So that obviously won't work. ! precedes only macro functions or arguments. #char, in your code, is neither, and it can't become one - can't read the data into the macro...
To give you a litte push forward: I understand you want the macro loop to run a different number of times for each variable, but you can't use char.length(!vr). I suggest instead have the macro loop as many times as necessary to be sure you can deal with the longest variable you'll need to work with.
And another general strategy hint - first, create syntax to deal with one specific variable and one specific delimiter. Once this works, start working on a macro, keeping in mind that the only purpose of the macro is to recreate the same working syntax, only changing the parameters of variable name and delimiter.
With my new understanding of the SPSS macro logic (thanks to #eli-k) the problem was quite easy to solve. Here is the working solution.
* DEFINE DATA.
DATA LIST /ID 1 (F) VAR1 2-5 (A) VAR2 6-12 (A).
BEGIN DATA
11, 28
21 1, 3
33, 12, 3, 1
4 2, 8
END DATA.
* DEFINE MACRO.
DEFINE #split_var(src_var = !TOKENS(1)
/dmmy_var_label = !DEFAULT(dmmy) !TOKENS(1)
/dmmy_var_lvls = !TOKENS(1))
NUMERIC !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls) (F1).
VECTOR #dmmy_vec = !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls).
STRING #char (A1).
LOOP #pos=1 TO char.length(!src_var).
COMPUTE #char = char.substr(!src_var, #pos, 1).
DO IF (#char NE "," AND #char NE " ").
COMPUTE #index = NUMBER(#char, F1).
COMPUTE #dmmy_vec(#index) = 1.
END IF.
END LOOP.
RECODE !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls) (SYSMIS=0) (ELSE=COPY).
EXECUTE.
!ENDDEFINE.
* CALL MACRO.
#split_var src_var=VAR2 dmmy_var_lvls=8.

Beginner question - why should I use nested loop in this example?

I’m trying to learn Swift. I’m now on lesson 5 of “Swift Tutorial for Beginners” by Code with Chris. I’m finishing all the challenges he prepared, but I’m stuck at Challenge 5, which is to print a pattern like this:
*
**
***
****
*****
I don’t get why should I use nested loop.
According to the completed challenge file, the code should look like this:
var drawPixel:String = "*"
var height:Int = 5
var tempRow:String = ""
for columnPixel in 1...height {
tempRow = ""
for _ in 1...columnPixel{
tempRow += drawPixel
}
print(tempRow)
}
but
var drawPixel:String = "*"
var height:Int = 5
var tempRow:String = ""
for _ in 1...height{
tempRow += drawPixel
print(tempRow)
}
also works the way it should and seems way simplier. I understand my method (second code), but not the one I’m supposed to use. My questions:
Why is there a nested loop?
why in first example nested loop refers to columnPixel (for _ in 1...columnPixel) since it is already defined that it should repeat the loop to 5?
Lastly, why "print(tempRow)" is outside of a nested loop?
Here's the challenge: https://docs.google.com/document/d/1DI-4RkYkRl8EPY17TOwfK8gCl--KMdqLEPP-hz6QHI0/edit# (scrool down to Challenge 5)
Thank you in advance!
Why is there a nested loop?
The outer loop and inner loop serve different purposes. Each iteration of the outer loop prints one row. Each iteration of the inner loop "constructs" the string that is printed.
why in first example nested loop refers to columnPixel (for _ in 1...columnPixel) since it is already defined that it should repeat the loop to 5?
columnPixel is referred in the inner loop because the number of iterations of the inner loop changes depending on which iteration of the outer loop:
In the first iteration of the outer loop, the inner loop loops only once. The string constructed is *
In the second iteration of the outer loop, the inner loop loops twice. The string constructed is **
In the third iteration of the outer loop, the inner loop loops three times. The string constructed is ***
and so on...
Notice that columnPixel changes with each iteration of the outer loop. In the first iteration it's 1, in the second iteration it's 2, etc. This is why we say "loop columnPixel lots of times" in the inner loop.
Lastly, why "print(tempRow)" is outside of a nested loop?
We only want to print the constructed string, not while we are constructing it.

Hash value is not re-initialized when loop is terminated with 'last' keyword

Consider the following nested loops:
my %deleted_documents_names = map { $_ => 1 }
$self->{MANUAL}->get_deleted_documents();
while($sth->fetch){
.....
.....
.....
while(my ($key, $value) = each(%deleted_documents_names)){
{
if($document_name eq $key){
$del_status=1;
last;
}
}
if($del_status==1){next;}
.....
.....
.....
.....
}
Now, I take a sample case where three values (A,B,C) will be compared against two values (B,C).
First scan:
A compared to B
A compared to C
Second scan:
B compared to B
Loop is terminated.
Third scan:
C is compared with C.
In this case, C should be compared first with B, being first value, but this comparison is skipped, and it only scans from the next element after the one that was found equal. If I remove last termination condition and let the loop run for total number of scans, then it works all fine, but I need to find out why in this case, $key refers to the next compared value and not to the first value once loop is restarted after getting terminated with last keyword.
Any help will be appreciated.
Use
keys %deleted_documents_names ; # Reset the "each" iterator.
See keys.
But, why are you iterating over the hash? Why don't you just
if (exists $deleted_documents_names{$document_name}) {
each() is a function that returns key-value pairs from a hash until it reaches the end. It is not aware of the scope it was called in, and doesn't know anything about your while loop logic. See the documentation here.
It can be reset by calling keys %hash or values %hash.
Update: however, as Choroba points out, you don't really need this loop. Your loop and accompanying logic could be replaced by this:
next if (exists $deleted_documents_names{$document_name});
(Hashes are designed with a structure that allows a key to be quickly found. In fact, this structure is what gives them the name "hashes". So doing it this way will be much more efficient than looping through all elements and testing each one).

Conditional IF/ELSE Statement in Matlab

I was trying to make a simple statement with Matlab as follows:
if TF==1
disp('One'), break
else continue
end
... ... ...
... ... ...
But even if TF is not 1, when I run the command, it doesn't CONTINUE to the rest of the script!! Any help would be appreciated-- Thanks
The continue statement has a very different meaning. Within a loop, like a for or while loop, continue instructs to skip the current round and continue with the next iteration in the loop. So if you remove continue, you will see the behavior that you are expecting. Here is an example:
for k = 1 : 10
if k == 4
% skip the calculation in the case where k is 4
continue
end
area = k * k;
disp(area);
end
When the loop iterates at k == 4, the block calculating the area of the corresponding square is skipped. This particular example is not very practical.
However, imagine you have a list of ten file names, and you want to process each file in this loop "for k = 1 : 10". You will have to try and open each file, but then if you find out the file does not exist, an appropriate way to handle it would be to print a little warning and then continue to the next file.

How to control nestedness of loops in Perl 6?

This program should've written triples of indices that have a sum less or equal to 7:
for ((1..7) X (1..7)) X (1..7) {
.say if [+] $_ <= 7;
}
I thought it would only loop over the top level of the list (and the code would have an error in the loop body then, but it's not the point), but it just loops over individual numbers, which is frustrating :( Is there a neat trick to avoid it? And BTW, is there a way to make an n-ary direct product?
the easiest way to to name the reference
for (1..7) X (1..7) -> $a, $b { }