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

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.

Related

Swift Programming Beginner : Why is there an error in my loop when implementing a Variable?

When I try and run my code in Xcode playground I get a warning:
Variable 'n' was never mutated; consider changing to 'let' constant.
First of all, I am changing the variable in the body of the loop so why is it telling me to change it to a let (constant) data type.
func multiples (n : Int) {
var n = 1
for _ in (3 ..< 1000) {
var n = n + 1
let multiple3 = 3 * n
print(multiple3)
}
}
I am changing the variable in the body of the loop
No, you’re not. The one in the body of the loop is a different n.
To fix that, change
var n = n + 1
To
n = n + 1
3 little notes:
a) If you read carefully messages from Xcode, you will understand about vars' lifetime and usage. ("Variable 'n' was never mutated; consider changing to 'let' constant" )
b) you have two var with same name in different scope
c) the you enter "for", n on the left will be computed using N in outer scope, so inner n will always be == 2
d) using debugger You will see as in picture.
Those are two different variables named n. One is unchanged and one is created for each new iteration of the for loop.
The reason you can have two variables with the same name is that they exist in different scopes and the one inside the for loop temporarily overrides the one outside the loop for the duration of the loop but only inside it.

Make the basis of a function from nest loop outer components

I have a segment of code where a composition of nested loops needs to be run at various times; however, each time the operations within the nested loops are different. Is there a way to make the outer portion (loop composition) somehow a functional piece, so that the internal operations are variable. For example, below, two code blocks are shown which both use the same loop introduction, but have different purposes. According to the principle of DRY, how can I improve this, so as not to need to repeat myself each time a similar loop needs to be used?
% BLOCK 1
for a = 0:max(aVec)
for p = find(aVec'==a)
iDval = iDauVec{p};
switch numel(iDval)
case 2
r = rEqVec(iDval);
qVec(iDval(1)) = qVec(p) * (r(2)^0.5 / (r(1)^0.5 + r(2)^0.5));
qVec(iDval(2)) = qVec(p) - qVec(iDval(1));
case 1
qVec(iDval) = qVec(p);
end
end
end
% BLOCK 2
for gen = 0:max(genVec)-1
for p = find(genVec'==gen)
iDval = iDauVec{p};
QinitVec(iDval) = QinitVec(p)/numel(iDval);
end
end
You can write your loop structure as a function, which takes a function handle as one of its inputs. Within the loop structure, you can call this function to carry out your operation.
It looks as if the code inside the loop needs the values of p and iDval, and needs to assign to different elements of a vector variable in the workspace. In that case a suitable function definition might be something like this:
function vec = applyFunctionInLoop(aVec, vec, iDauVec, funcToApply)
for a = 0:max(aVec)
for p = find(aVec'==a)
iDval = iDauVec{p};
vec = funcToApply(vec, iDval, p);
end
end
end
You would need to put the code for each different operation you want to carry out in this way into a function with suitable input and output arguments:
function qvec = myFunc1(qVec, iDval, p)
switch numel(iDval)
case 2
r = rEqVec(iDval); % see note
qVec(iDval(1)) = qVec(p) * (r(2)^0.5 / (r(1)^0.5 + r(2)^0.5));
qVec(iDval(2)) = qVec(p) - qVec(iDval(1));
case 1
qVec(iDval) = qVec(p);
end
end
function v = myFunc2(v, ix, q)
v(ix) = v(q)/numel(ix);
end
Now you can use your loop structure to apply each function:
qvec = applyFunctionInLoop(aVec, qVec, iDauVec, myFunc1);
QinitVec = applyFunctionInLoop(aVec, QinitVec, iDauVec, myFunc2);
and so on.
In most of the answer I've kept to the same variable names you used in your question, but in the definition of myFunc2 I've changed the names to emphasise that these variables are local to the function definition - the function is not operating on the variables you passed in to it, but on the values of those variables, which is why we have to pass the final value of the vector out again.
Note that if you want to use the values of other variables in your functions, such as rEqVec in myFunc1, you need to think about whether those variables will be available in the function's workspace. I recommend reading these help pages on the Mathworks site:
Share Data Between Workspaces
Dynamic Function Creation with Anonymous and Nested Functions

How do get loop results into a vector or matrix in matlab

Here is the thing:
I have while loop nested in a for loop.
I can get the results of each iteration as a result for the variable flp. But now i want all these results stored in a vector with same number of rows as another variable called eci. I'm aware that i have to preallocate the vector. But how do i move on from here?
Tank you!
Here is the code i've done so far:
for eci=0:0.0002:ecu
fl=0;
fcc=fc0*(2.254*sqrt(1+7.94*fl/fc0)-2*fl/fc0-1.254);
ecc=ec0*(1+5*(fcc/fc0-1));
r=Ec/(Ec-fcc/ecc);
x=eci/ecc;
fc=fcc*x*r/(r-1+x^r);
el=(Ec*eci-fc)/(2*beta*fc);
flp=ke*kr*2*nf*tf*Ef*1000*el/B;
while abs(fl-flp)>0.0001
fl=flp;
fcc=fc0*(2.254*sqrt(1+7.94*fl/fc0)-2*fl/fc0-1.254);
ecc=ec0*(1+5*(fcc/fc0-1));
r=Ec/(Ec-fcc/ecc);
x=eci/ecc;
fc=fcc*x*r/(r-1+x^r);
el=(Ec*eci-fc)/(2*beta*fc);
flp=ke*kr*2*nf*tf*Ef*1000*el/B
end
end
eci=[0:0.0002:ecu]';
m=size(eci);
m(:,2)=[];
mat_result=zeros(m,1)
Its quite stimple, start with an empty vector, for example:
results = zeros(length(0:0.0002:ecu),1);
Then just start counting with t=t+1 somewhere in the loop (initialize properly ofcourse) and store the restult:
results(t) = myResult

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).

Breaking/Continuing nested for loops in 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.