C-Style i++ for is deprecated in swift issue - swift

I want to increment index at some point for this loop it prints 1,3,5 which is i want to. I get the warning
C-Style for statement is deprecated and ...
i know what it means.
for var index=0; index<5; index++ {
//If condition A == true
index++
//else without index++
print(index) // print 1, 3, 5
}
So i changed it to:
for var index in 0..<5 {
//If condition A == true
index += 1
//else without index++
print(index) // print 1,2,3,4,5 Should 1,3,5 from my side
}
I just wondering why index not mutable? Even though i have set it to var or any solutions for my issue.

The index is not mutable because
for var x in y {
...
}
is equivalent to
for temp in y {
var x = temp
...
}
where the var just makes x a copy of temp. When you modify x, it won't modify the real index temp (This is also a reason why SE-0003 is introduced)
The C-style for loop can just be reduced to a while loop:
var index = 0
while index < 5 {
if conditionA {
index += 1
}
print(index)
index += 1
}

If you just need to enumerate odd numbers, the simplest way will be to use stride:
for i in 1.stride(through: 5, by: 2) {
print(i) // prints 1, 3, 5
}

Here is one way to get the results you want:
for var index in 0..<3 {
print(2 * index + 1)
}

I believe swift loop variables are immutable when using the for in loop. Mutating a loop variable inside the loop is usually (one could argue always) a bad idea so it makes sense the swift designers didn't allow it. The desired result can be accomplished in cleaner ways, for instance using continue.
for i in 1...5
{
if i%2==0
{
continue
}
print(i)
}

Related

Extremely basic loop question telling whether number is even/odd

var currentnum: Int = 1
for currentnum in 1...100{
if (currentnum % 2) != 0 {
print("Odd number")
}
else{
print("Even number")
}
currentnum += 1
}
Hello. I'm trying to "create a loop that iterates from 1 to 100 that prints out whether the current number in the iteration is even or odd." When I run the above code, I receive "error: expected expression after operator." What is wrong with my code (I'm new to programming). Thanks!
You don't need to declare var currentnum: Int = 1 in your code and increment through currentnum += 1. for-in loop does it for you. In Swift for-in syntax can be used to loop over both ranges of numbers, collections and even strings. All with the same syntax!
It should be as follows,
for currentnum in 1...100{
if (currentnum % 2) != 0 {
print("Odd number")
}
else{
print("Even number")
}
}
Good luck!
You should get rid of this expression currentnum += 1.
Because you are using the In .. Range operator there is no need to increment the counter. The In .. Range Operator will take care of this. This is different to the basic for loop from Java or C++ where you need to increment your counter variable.
Additionally the first declared variable currentnum is never used. This variable could be removed too.
The rest of your algorithm looks good and should work!
Hope this helps!
Unlike some languages you do not need to define the index variable before entering the for-in loop, nor do you need to manually increment the index.
You can also use the new swift function isMultiple(of:) rather than modulus
If you want to loop through a set range you can do:
for num in 1...100 {
if num.isMultiple(of: 2) {
print("\(num) is an even number")
} else {
print("\(num) is an odd number")
}
}
If you have a set of values in an array you can do this:
let numbers = [1,5,12,23,25,27,30,32,35]
for num in numbers {
if num.isMultiple(of: 2) {
print("\(num) is an even number")
} else {
print("\(num) is an odd number")
}
}
One liner without a for loop per the request in the comments
Array(1...100).map{$0 % 2 == 0 ? print("\($0) is even") : print("\($0) is odd") }
#BeginnerCoderGirl i have changed your code please check just remove currentnum += 1 from code and run

Swift Forin-where perform filter or skip (continue)?

I just gain a knowledge about Swift's forin-where, but it seems very lack of documents. So there's a question in my mind: Does it perform filter then loop or just loop with condition? given the below code
var arr = [1, 2, 3, 4, 5]
for i in arr where i > 3 {
print(i)
}
does the machine do like this:
for i in arr.filter { $0 > 3 }
or like this?
for i in arr {
guard i > 3 else { continue }
print(i)
}
Should I use forin-where or just filter then foreach?
It is the latter (iterate over all elements, execute the body only for
elements satisfying the condition).
The for-statements takes an arbitrary sequence, not only arrays.
Filtering the sequence first would not only be inefficient (memory- and
time-wise), but also impossible for sequences producing “infinitely many” values, like in this example:
for x in 1... where x % 3 == 0 {
print(x)
if x > 10 { break }
}
Here 1... is a “partial range” representing all integers greater than
or equal to one.

safely remove item while iterating backward in Swift 3

When I want to pass through and remove an item or items from an array (when certain conditions are met), I typically iterate backward in the C-style for-loop and remove the item by index, avoiding the problem of index numbers being changed of the next item to be processed, or the changing size of the list affecting how many times the loop is passed through. But the C for-loop has been removed in Swift 3.
Here is my Swift 2.3 code for the initialization of the loop:
for (var i = allowedItems.count - 1; i > -1; i -= 1)
Here is the monstrosity created by the Swift 3 converter:
for (i in ((-1 + 1)...allowedItems.count - 1).reversed())
This version does not compile however. ("Expected ',' separator" at the "in" operator).
I simplify the "-1 + 1" bit to zero:
for (i in (0...allowedItems.count - 1).reversed())
Now the error is "Expected Sequence expression for for-each loop".
What is the safe and hopefully reasonably elegant way of iterating backward in Swift 3, in which an index or counter variable is made available for use in specifying which item should be removed? This type of logic appears a number of places in my code so I want to make sure to find the best solution.
Thanks.
What is the safe and hopefully reasonably elegant way of iterating backward in Swift 3
The built-in way is:
for i in (0 ..< allowedItems.count).reversed()
The elegant way is:
for i in allowedItems.count >>> 0
(where >>> is the custom operator that I define here).
Use stride:
for i in stride(from: allowedItems.count - 1, through: 0, by: -1) {
}
What is the safe and hopefully reasonably elegant way of iterating
backward in Swift 3, in which an index or counter variable is made
available for use in specifying which item should be removed?
This doesn't answer the technical question, but possibly the underlying XY problem: have you considered simply filtering your array based on the criteria "when certain conditions are met"?
func certainConditionsForKeepingAreMet(_ element: YourElementType) -> Bool { /* ... */ }
allowedItems = allowedItems.filter(certainConditionsForKeepingAreMet)
E.g.
var allowedItems = [1, 3 ,6, 2]
func certainConditionsForKeepingAreMet(_ element: Int) -> Bool { return element < 3 }
allowedItems = allowedItems.filter(certainConditionsForKeepingAreMet)
print(allowedItems) // [1, 2]
If you'd like to remove and use the removed elements (on-the-fly), you could simply pipe the elements that are to be removed to some "use this element" function, in the course of checking the conditions for the elements.
func doSomethingWith(_ element: Int) { print("Removed", element) }
func certainConditionsForKeepingAreMet(_ element: Int) -> Bool {
if element >= 3 {
doSomethingWith(element)
return false
}
return true
}
var allowedItems = [1, 3 ,6, 2]
allowedItems = allowedItems.filter(certainConditionsForKeepingAreMet)
/* Removed 3
Removed 6 */
print(allowedItems) // [1, 2]

Index out of range in Swift with removeAtIndex

I tried to remove an element in NSUserDefaults which is the same as stockSymbol's value when click a button. My idea is that cast the NSUserDefaults to an array and remove the element with removeAtIndex. Here is my code.
#IBAction func buttonFilledStarClicked(sender: AnyObject) {
NSLog("Filled star clicked")
self.buttonFilledStar.hidden = true
self.buttonEmptyStar.hidden = false
var Array = NSUserDefaults.standardUserDefaults().objectForKey("favorites")! as! [String]
var countArray = (NSUserDefaults.standardUserDefaults().objectForKey("favorites")! as! [String]).count - 1
for i in 0...countArray {
if stockSymbol! == Array[i] {
NSLog("i is : \(i)")
Array.removeAtIndex(i)
}
else {}
}
NSLog("Array is: \(Array), countArray is: \(countArray)")
}
However it has 'out of index' error.
It works when I just comment Array.removeAtIndex(i) out.
Array looks like this --
["aa", "bb", "Test!", "Test!"]
Any suggestions? Thank you in advance.
So, the change you can make to resolve the error with the least impact on your code overall would be to simply iterate through the indices backwards:
for i in (0...countArray).reverse() {
if stockSymbol! == Array[i] {
NSLog("i is : \(i)")
Array.removeAtIndex(i)
}
else {}
}
But the best option is to just use Swift's filter:
Array = Array.filter { $0 != stockSymbol }
An expanded note on why the crash is happening...
Let's take a simplified example. Say I have the following array:
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
And I want to remove all of the odd numbers out of it. Using your first naïve approach, I might write my logic like this:
for i in 0..<arr.count {
if arr[i] % 2 != 0 {
arr.removeAtIndex(i)
}
}
Look at what happens on each iteration.
On the first iteration, we have arr[i] of 1. This is an odd number, so we'll removeAtIndex, and our array now actually looks like this:
[2, 3, 4, 5, 6, 7, 8, 9, 10]
The array's size is now smaller--it has just 9 elements. But the loop doesn't work like an old C-style for loop where i < arr.count is checked on each iteration (which is part of why this loop is faster).
But notice something else that happens when we iterate forward...
On the second iteration, i is equal to 1, and so what does arr[i] give us? It gives us 3. We never even check 2. On the first iteration, when i was 0, it was at index 1. On the second iteration, when i is 1, the 2 is at index 0.
So on the second iteration, we'll call removeAtIndex with i equal to 1 and remove the 3.
This pattern will continue for a few iterations until we end up with our array of just even numbers:
[2, 4, 6, 8, 10]
But this happens after the iteration where i was equal to 4, and the loop is going to try running until i is equal to 10.
On the sixth iteration of the loop, we try to access the element at index 5 of the array. But the array only has five elements, so the largest index is 4. When we try to access index 5, we crash.
You should not remove it from inside of the loop, when you call removeAtIndex(i) Array removes the item so you have 1 less item then countArray.. so you have to have another array to remember which item you want to remove and remove it outside of the loop.. or better option is to use filter
// Filter only strings that match stockSymbol
Array = Array.filter { $0 == stockSymbol! }
Try to find out which i that give you index out of range result. Is it the 0 or the last one. Maybe you will find some other useful clue.
First of all Array is a type, maybe you can call:
var favourites = NSUserDefaults.standardUserDefaults().objectForKey("favorites")! as! [String]
Then you don't need a array's count variable you can access using count arrays property.
Finally if you are iterating through an array and remove an element it always going to throw "index's error" because the index is not the same as the beginning..
For solving this you can take two pointers of the index variable, but what I would do is something like this:
var correctElements = favourites.filter({$0!=stockSymbol})

In Swift 2.2, how to consolidate the for-loop statement?

In Swift 2.2, C-style for statement is deprecated, so I modify following for-loop:
for var idx=data.count-1; idx>=0; --idx
into
for idx in (0...data.count-1).reverse() // <--- new statement
However, I found, when data.count is 0 during execution, the new statement will crash with error fatal error: Can't form range with end < start.
Is there a best/standard way to code for this case?
P.S. I think I have to use different kinds of loops/syntax to replace my unified C-style loops. Any further comment or suggestion on this is welcome.
Creating a range as
0 ... data.count-1
terminates with a runtime exception if data.count is zero. It is
often better to use the ..< operator to make a range that
omits its upper value, in your case:
0 ..< data.count
This works for data.count == 0 as well and creates an empty
range in that case. This applies to
both forward and backward iteration:
for idx in 0 ..< data.count { ... }
for idx in (0 ..< data.count).reverse() { ... }
(Of course stride() is a sensible alternative for the second case.)
You should use Strideable.stride(through:by:) to generate your for-loop range, like this:
for idx in (data.count-1).stride(through: 0, by: -1) {
print(idx)
}
It works even if data.count == 0.
In such a simple loop, there is no need for arithmetic operations.
If data is an array, use indices:
for index in data.indices {
}
for index in data.indices.reverse() {
}
or access the data directly
for item in data {
}
for item in data.reverse() {
}
or a combination of the previous using enumerate
for (index, item) in data.enumerate() {
}
Note that all for-in loops above can be also written as forEach:
data.indices.forEach {
}
Instead, use for idx in (0..<data.count).reverse(). This will form the empty range that you want when data.count == 0.