I have a 'for' loop similar to this:
for i in 0...n - 1 {
// do stuff, n is not changed
}
Back in the day, when I coded in FORTRAN, I was taught that this was a very inefficient way to code large 'for' loops.
Does the Swift compiler recognize the non-changing limit and pre-calculate n - 1?
I think the answer is yes.
1...n - 1 represents a Range object. It is a literal of Range. Therefore, when compilation reaches the loop and sees the literal, it thinks
It seems like that you want to create a new Range<Int> object! Here you go! Hmm... So I guess i is of type Int...
and so on.
This means that n - 1 is evaluated when you create the object. And it stays that way, not evaluating it a second time. This code proves it by not printing only one hello:
var n = 10
for i in 1...n - 1 {
n = 2
print("Hello")
}
So yeah.
Note:
It's better to use 1..<n instead of 1...n - 1 in this case, they are the same.
Apple actually recommends you to use this approach instead of the C-style for loop.
The C-style for loop will be removed in Swift 3
Related
I want to print integer numbers from 1 to a random integer number (e.g. to a random integer number < 10 like in the following case). I can use e.g. one from the following ways:
1)
val randomNumber=r.nextInt(10)
for (i <- 0 to randomNumber) {println(i)}
2)
for (i <- 0 to r.nextInt(10)) {println(i)}
My question is the following. Is there a difference between 1) and 2) in the sense of computation? It is clear that a random number r.nextInt(10) is computed only once and after that it is assigned to
the variable randomNumber in the first case but what about the second case? Is the part r.nextInt(10) computed only once at the beginnig of the loop or it is computed for each iteration of the loop? If yes then the first variant is better from computation point of view? I know that this proposed example is an easy example but there can be much more complex for loops where the optimization can be very helpful. If the expression r.nextInt(10) in the second case is computed only once what about expressions which are e.g. functions of variable i, something like for (i <- 0 to fce(i)) {println(i)}? I guess that Fce(i) should be evaluated in every iteration of loop.
Thanks for help.
Andrew
No, there are no differences between 1) and 2).
The bound for the for loop will be evaluated once, and then the for loop will repeat this now fixed number of times.
Things would have been very different comparing those two pieces of code :
val randomNumber=r.nextInt(10)
for (i <- 0 to 10) {println(randomNumber)}
and
for (i <- 0 to 10) {println(r.nextInt(10))}
The first for loop will print 10 times the same value, the second will print 10 random values.
But you could still rewrite the second as
def randomNumber=r.nextInt(10)
for (i <- 0 to 10) {println(randomNumber)}
The change from a val to a function will cause a reevaluation every time the loop is executed.
Now, about
for (i <- 0 to function(i)) {doSomething()}
This doesn't compile. The variable i is only available in the scope between the {} of the for loop, and hence not for computing the loop bounds.
I hope this clarifies things a bit !
The two versions do the same thing, and to see why you need to realise that for in Scala works very differently from how it works in other languages like C/C++.
In Scala, for is just a bit of syntax that makes it easier to chain map/foreach, flatMap, and withFilter methods together. It makes functional code appear more like imperative code, but it is still executed in a functional way.
So your second chunk of code
for (i <- 0 to r.nextInt(10)) {println(i)}
is changed by the compiler into something like
(0 to r.nextInt(10)).foreach{ i => println(i) }
Looking at it this way, you can see that the range is computed first (using a single call to nextInt) and then foreach is called on that range. Therefore nextInt is called the same number of times as in your first chunk of code.
I already posted on the Apple Dev Forums but didn't get any response, so apologies if you've already seen this. I have a new (potential) bug I'm seeing in Beta 5 and I'm wondeirng if anyone has a workaround.
This line was working fine in Beta 4:
for i in 0 ... tiledMap.mapSize.width {
tiledMap.mapSize.width is a CGFloat
In beta 5, Swift complains:
'ClosedInterval<T>' does not have a member named 'Generator'
If I switch tileMap.mapSize.width to a constant like 25, the code compiles of course:
for i in 0 ... 25 {
This doesn't seem to be defined in the Swift book, but think it's reasonable that the range operators ... and ..< don't work for floating types (Float, Double, CGFloat...) in for ... in loops. I think that might lead to confounded expectations and confusion, as floating types don't really have a sensible set of values to step through in the ranges between two of their values.
You could argue that the ranges should step through the integer values in between the start and end points, but (a) there may not be a precise float representation of a given integer, and (b) what happens if the start and end points aren't integer in the first place? (e.g. for i in 0.3846...837.8) Some might even expect for ... in to loop through all possible floating values in the range—that's what happens for integers.
To me, the language design is good here: if you want to step through certain points between two float values, you should have to make it explicit and use a different loop construct that makes it clearer what's going on:
for var i:CGFloat = 0; i <= tiledMap.mapSize.width; i++ {
It's worth nothing that floats are strideable, too:
for i in stride(from: 0.0, through: tiledMap.mapSize.width, by: 1.0) {
I have a matrix of two columns and six rows, and want to build a second one with the following code:
for i=2
if F(:,i)<50
G(:,i) = 1
end
end
But nothing happens...
The idea was that if a value in the second column in F was less than 50, then the corresponding value in G would be 1.
Sorry for probably basic question, but no idea why this doesn't work. If I change to evaluate whether the F value ~= 50, then everything works as it should.
Thanks for any help.
Your if statement is only executed once - not once per element. While F(:,i)<50 returns an array of values, the if is either true or false; consequently, the next line is only executed once (either on all elements in G(:,i), or none of them).
For example, see this piece of code:
if(1 < [0 1 2]), disp('true'); end
It will produce no output, even though it is true for the third element. On the other hand,
if(1 < [2 3 4]), disp('true'); end
does produce output...
In general, the following:
1 < [0 1 2]
produces
0 0 1
Not sure why you say it doesn't work for < but it does work for ~=. Maybe there are no elements equal to 50, so it only "seems" to work?
In general, there is a better way to do what you want, with a single line:
G(F(:,2)<50,2)=1
This uses "logical indexing", and is much faster than looping. It will consider each element of F(:,2), and modify the corresponding element in G.
One final comment: it is not great practice to use the variable i since it has a built in value of sqrt(-1). If you have code anywhere that relies on it having that value, then accidentally overwriting it with any other value would break that. It's not the problem with your code today - but why set yourself up for a problem in the future.
In Matlab, suppose I would like to create a 0-vector of length L, except with a 1 at index i?
For example, something like:
>> mostlyzeros(6, 3)
ans =
0 0 1 0 0 0
The purpose is so I can use it as a 'selection' vector which I'll multiply element-wise with another vector.
The simplest way I can think of is this:
a = (1:N)==m;
where N>=m. Having said that, if you want to use the resulting vector as a "selection vector", I don't know why you'd multiply two vectors elementwise, as I would expect that to be relatively slow and inefficient. If you want to get a vector containing only the m-th value of vector v in the m-th position, this would be a more straightforward method:
b = ((1:N)==m)*v(m);
Although the most natural method would have to be this:
b(N)=0;
b(m)=v(m);
assuming that b isn't defined before this (if b is defined, you need to use zeros rather than just assigning the Nth value as zero - it has been my experience that creating a zero vector or matrix that didn't exist before that is most easily done by assigning the last element of it to be zero - it's also useful for extending a matrix or vector).
I'm having a hard time thinking of anything more sensible than:
Vec = zeros(1, L);
Vec(i) = 1;
But I'd be happy to be proven wrong!
UPDATE: The one-liner solution provided by #GlenO is very neat! However, be aware that if efficiency is the chief criteria, then a few speed tests on my machine indicate that the simple method proposed in this answer and the other two answers is 3 or 4 times faster...
NEXT UPDATE: Ah! So that's what you mean by "selection vectors". #GlenO has given a good explanation of why for this operation a vector of ones and zeros is not idiomatic Matlab - however you choose to build it.
ps Try to avoid using i as a subscript, since it is actually a matlab function.
Just for the fun of it, another one-liner:
function [out] = mostlyzeros(idx, L)
out([L, idx]) = [0 1];
I can think of:
function mostlyones(m,n)
mat=zeros(1,m);
mat(n)=1;
Also, one thing to note. In MATLAB, index starts from one and not from zero. So your function call should have been mostlyzeros(6,3)
I would simply create a zero-vector and change whatever value you like to one:
function zeroWithOne(int numOfZeros, int pos)
a = zeros(numOfZeros,1);
a(pos) = 1;
Another one line option, which should be fast is:
vec = sparse(1, ii, 1, 1, L);
So I'm completely new to MATLAB and I'm trying to understand colon notation within mathematical operations. So, in this book I found this statement:
w(1:5)=j(1:5) + k(1:5);
I do not understand what it really does. I know that w(1:5) is pretty much iterating through the w array from index 1 through 5, but in the statement above, shouldn't all indexes of w be equal to j(5) + k(5) in the end? Or am I completely wrong on how this works? It'd be awesome if someone posted the equivalent in Java to that up there. Thanks in advance :-)
I am pretty sure this means
"The first 5 elements of w shall be the first 5 elements of j + the first 5 elements of k" (I am not sure if matlab arrays start with 0 or 1 though)
So:
w1 = j1+k1
w2 = j2+k2
w3 = j3+k3
w4 = j4+k4
w5 = j5+k5
Think "Vector addition" here.
w(1:5)=j(1:5) + k(1:5);
is the same that:
for i=1:5
w(i)=j(i)+k(i);
end
MATLAB uses vectors and matrices, and is heavily optimized to handle operations on them efficiently.
The expression w(1:5) means a vector consisting of the first 5 elements of w; the expression you posted adds two 5 element vectors (the first 5 elements of j and k) and assigns the result to the first five elements of w.
I think your problem comes from the way how do you call this statement. It is not an iteration, but rather simple assignment. Now we only need to understand what was assigned to what.
I will assume j,k, w are all vectors 1 by N.
j(1:5) - means elements from 1 to 5 of the vector j
j(1:5) + k(1:5) - will result in elementwise sum of both operands
w(1:5) = ... - will assign the result again elementwise to w
Writing your code using colon notation makes it less verbose and more efficient. So it is highly recommended to do so. Also, colon notation is the basic and very powerful feature of MATLAB. Make sure you understand it well, before you move on. MATLAB is very well documented so you can read on this topic here.