I have following line in my code:
for (i = 0, j = count - 1; i < count; j = i++)
Can anyone help to remove the two compiler warnings, that i++ will be removed in Swift 3.0 and C-style for statement is depreciated?
You could use this:
var j = count-1
for i in 0..<count {
defer { j = i } // This will keep the cycle "logic" all together, similarly to "j = i++"
// Cycle body
}
EDIT
As #t0rst noted, be careful using defer, since it will be executed no matter how its enclosing scope is exited, so it isn't a 100% replacement.
So while the standard for ( forInit ; forTest ; forNext ) { … } will not execute forNext in case of a break statement inside the cycle, a return or an exception, the defer will.
Read here for more
Alternatively, lets go crazy to avoid having to declare j as external to the loop scope!
Snippet 1
let count = 10
for (i, j) in [count-1..<count, 0..<count-1].flatten().enumerate() {
print(i, j)
}
/* 0 9
1 0
2 1
3 2
4 3
5 4
6 5
7 6
8 7
9 8 */
Snippet 2
for (i, j) in (-1..<count-1).map({ $0 < 0 ? count-1 : $0 }).enumerate() {
print(i, j)
}
Trying to win the prize for the craziest solution in this thread
Snippet 1
extension Int {
func j(count:Int) -> Int {
return (self + count - 1) % count
}
}
for i in 0..<count {
print(i, i.j(count))
}
Snippet 2
let count = 10
let iList = 0..<count
let jList = iList.map { ($0 + count - 1) % count }
zip(iList, jList).forEach { (i, j) in
print(i, j)
}
You could use a helper function to abstract away the wrapping of j as:
func go(count: Int, block: (Int, Int) -> ()) {
if count < 1 { return }
block(0, count - 1)
for i in 1 ..< count {
block(i, i - 1)
}
}
Related
I want to add the numbers together and print every 4 elements, however i cannot wrap my head around using the stride function, if i am using the wrong approach please explain a better method
var numbers = [1,2,3,4,5,6,7,8,9,10,11,12,13]
func addNumbersByStride(){
var output = Stride...
//first output = 1+2+3+4 = 10
//second output = 5+6+7+8 = 26 and so on
print(output)
}
It seems you would like to use stride ...
let arr = [1,2,3,4,5,6,7,8,9,10,11,12,13]
let by = 4
let i = stride(from: arr.startIndex, to: arr.endIndex, by: by)
var j = i.makeIterator()
while let n = j.next() {
let e = min(n.advanced(by: by), arr.endIndex)
let sum = arr[n..<e].reduce(0, +)
print("summ of arr[\(n)..<\(e)]", sum)
}
prints
summ of arr[0..<4] 10
summ of arr[4..<8] 26
summ of arr[8..<12] 42
summ of arr[12..<13] 13
You can first split the array into chunks, and then add the chunks up:
extension Array {
// split array into chunks of n
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}
// add each chunk up:
let results = numbers.chunked(into: 4).map { $0.reduce(0, +) }
If you would like to discard the last sum if the length of the original array is not divisible by 4, you can add an if statement like this:
let results: [Int]
if numbers.count % 4 != 0 {
results = Array(numbers.chunked(into: 4).map { $0.reduce(0, +) }.dropLast())
} else {
results = numbers.chunked(into: 4).map { $0.reduce(0, +) }
}
This is quite a basic solution and maybe not so elegant. First calculate and print sum of every group of 4 elements
var sum = 0
var count = 0
for n in stride(from: 4, to: numbers.count, by: 4) {
sum = 0
for i in n-4..<n {
sum += numbers[i]
}
count = n
print(sum)
}
Then calculate the sum of the remaining elements
sum = 0
for n in count..<numbers.count {
sum += numbers[n]
}
print(sum)
I am trying to solve the task
Using a standard for-in loop add all odd numbers less than or equal to 100 to the oddNumbers array
I tried the following:
var oddNumbers = [Int]()
var numbt = 0
for newNumt in 0..<100 {
var newNumt = numbt + 1; numbt += 2; oddNumbers.append(newNumt)
}
print(oddNumbers)
This results in:
1,3,5,7,9,...199
My question is: Why does it print numbers above 100 although I specify the range between 0 and <100?
You're doing a mistake:
for newNumt in 0..<100 {
var newNumt = numbt + 1; numbt += 2; oddNumbers.append(newNumt)
}
The variable newNumt defined inside the loop does not affect the variable newNumt declared in the for statement. So the for loop prints out the first 100 odd numbers, not the odd numbers between 0 and 100.
If you need to use a for loop:
var odds = [Int]()
for number in 0...100 where number % 2 == 1 {
odds.append(number)
}
Alternatively:
let odds = (0...100).filter { $0 % 2 == 1 }
will filter the odd numbers from an array with items from 0 to 100. For an even better implementation use the stride operator:
let odds = Array(stride(from: 1, to: 100, by: 2))
If you want all the odd numbers between 0 and 100 you can write
let oddNums = (0...100).filter { $0 % 2 == 1 }
or
let oddNums = Array(stride(from: 1, to: 100, by: 2))
Why does it print numbers above 100 although I specify the range between 0 and <100?
Look again at your code:
for newNumt in 0..<100 {
var newNumt = numbt + 1; numbt += 2; oddNumbers.append(newNumt)
}
The newNumt used inside the loop is different from the loop variable; the var newNumt declares a new variable whose scope is the body of the loop, so it gets created and destroyed each time through the loop. Meanwhile, numbt is declared outside the loop, so it keeps being incremented by 2 each time through the loop.
I see that this is an old question, but none of the answers specifically address looping over odd numbers, so I'll add another. The stride() function that Luca Angeletti pointed to is the right way to go, but you can use it directly in a for loop like this:
for oddNumber in stride(from:1, to:100, by:2) {
// your code here
}
stride(from:,to:,by:) creates a list of any strideable type up to but not including the from: parameter, in increments of the by: parameter, so in this case oddNumber starts at 1 and includes 3, 5, 7, 9...99. If you want to include the upper limit, there's a stride(from:,through:,by:) form where the through: parameter is included.
If you want all the odd numbers between 0 and 100 you can write
for i in 1...100 {
if i % 2 == 1 {
continue
}
print(i - 1)
}
For Swift 4.2
extension Collection {
func everyOther(_ body: (Element) -> Void) {
let start = self.startIndex
let end = self.endIndex
var iter = start
while iter != end {
body(self[iter])
let next = index(after: iter)
if next == end { break }
iter = index(after: next)
}
}
}
And then you can use it like this:
class OddsEvent: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
(1...900000).everyOther{ print($0) } //Even
(0...100000).everyOther{ print($0) } //Odds
}
}
This is more efficient than:
let oddNums = (0...100).filter { $0 % 2 == 1 } or
let oddNums = Array(stride(from: 1, to: 100, by: 2))
because supports larger Collections
Source: https://developer.apple.com/videos/play/wwdc2018/229/
How do I write the following in Swift3?
for (f = first; f <= last; f += interval)
{
n += 1
}
This is my own attempt
for _ in 0.stride(to: last, by: interval)
{
n += 1
}
Swift 2.2 -> 3.0: Strideable:s stride(...) replaced by global stride(...) functions
In Swift 2.2, we can (as you've tried in your own attempt) make use of the blueprinted (and default-implemented) functions stride(through:by:) and stride(to:by:) from the protocol Strideable
/* Swift 2.2: stride example usage */
let from = 0
let to = 10
let through = 10
let by = 1
for _ in from.stride(through, by: by) { } // from ... through (steps: 'by')
for _ in from.stride(to, by: by) { } // from ..< to (steps: 'by')
Whereas in Swift 3.0, these two functions has been removed from Strideable in favour of the global functions stride(from:through:by:) and stride(from:to:by:); hence the equivalent Swift 3.0 version of the above follows as
/* Swift 3.0: stride example usage */
let from = 0
let to = 10
let through = 10
let by = 1
for _ in stride(from: from, through: through, by: by) { }
for _ in stride(from: from, to: to, by: by) { }
In your example you want to use the closed interval stride alternative stride(from:through:by:), since the invariant in your for loop uses comparison to less or equal to (<=). I.e.
/* example values of your parameters 'first', 'last' and 'interval' */
let first = 0
let last = 10
let interval = 2
var n = 0
for f in stride(from: first, through: last, by: interval) {
print(f)
n += 1
} // 0 2 4 6 8 10
print(n) // 6
Where, naturally, we use your for loop only as an example of the passage from for loop to stride, as you can naturally, for your specific example, just compute n without the need of a loop (n=1+(last-first)/interval).
Swift 3.0: An alternative to stride for more complex iterate increment logic
With the implementation of evolution proposal SE-0094, Swift 3.0 introduced the global sequence functions:
sequence(first:next:),
sequence(state:next:),
which can be an appropriate alternative to stride for cases with a more complex iterate increment relation (which is not the case in this example).
Declaration(s)
func sequence<T>(first: T, next: #escaping (T) -> T?) ->
UnfoldSequence<T, (T?, Bool)>
func sequence<T, State>(state: State,
next: #escaping (inout State) -> T?) ->
UnfoldSequence<T, State>
We'll briefly look at the first of these two functions. The next arguments takes a closure that applies some logic to lazily construct next sequence element given the current one (starting with first). The sequence is terminated when next returns nil, or infinite, if a next never returns nil.
Applied to the simple constant-stride example above, the sequence method is a bit verbose and overkill w.r.t. the fit-for-this-purpose stride solution:
let first = 0
let last = 10
let interval = 2
var n = 0
for f in sequence(first: first,
next: { $0 + interval <= last ? $0 + interval : nil }) {
print(f)
n += 1
} // 0 2 4 6 8 10
print(n) // 6
The sequence functions become very useful for cases with non-constant stride, however, e.g. as in the example covered in the following Q&A:
Express for loops in swift with dynamic range
Just take care to terminate the sequence with an eventual nil return (if not: "infinite" element generation), or, when Swift 3.1 arrives, make use of its lazy generation in combination with the prefix(while:) method for sequences, as described in evolution proposal SE-0045. The latter applied to the running example of this answer makes the sequence approach less verbose, clearly including the termination criteria of the element generation.
/* for Swift 3.1 */
// ... as above
for f in sequence(first: first, next: { $0 + interval })
.prefix(while: { $0 <= last }) {
print(f)
n += 1
} // 0 2 4 6 8 10
print(n) // 6
With Swift 5, you may choose one of the 5 following examples in order to solve your problem.
#1. Using stride(from:to:by:) function
let first = 0
let last = 10
let interval = 2
let sequence = stride(from: first, to: last, by: interval)
for element in sequence {
print(element)
}
/*
prints:
0
2
4
6
8
*/
#2. Using sequence(first:next:) function
let first = 0
let last = 10
let interval = 2
let unfoldSequence = sequence(first: first, next: {
$0 + interval < last ? $0 + interval : nil
})
for element in unfoldSequence {
print(element)
}
/*
prints:
0
2
4
6
8
*/
#3. Using AnySequence init(_:) initializer
let anySequence = AnySequence<Int>({ () -> AnyIterator<Int> in
let first = 0
let last = 10
let interval = 2
var value = first
return AnyIterator<Int> {
defer { value += interval }
return value < last ? value : nil
}
})
for element in anySequence {
print(element)
}
/*
prints:
0
2
4
6
8
*/
#4. Using CountableRange filter(_:) method
let first = 0
let last = 10
let interval = 2
let range = first ..< last
let lazyCollection = range.lazy.filter({ $0 % interval == 0 })
for element in lazyCollection {
print(element)
}
/*
prints:
0
2
4
6
8
*/
#5. Using CountableRange flatMap(_:) method
let first = 0
let last = 10
let interval = 2
let range = first ..< last
let lazyCollection = range.lazy.compactMap({ $0 % interval == 0 ? $0 : nil })
for element in lazyCollection {
print(element)
}
/*
prints:
0
2
4
6
8
*/
Simply, working code for Swift 3.0:
let (first, last, interval) = (0, 100, 1)
var n = 0
for _ in stride(from: first, to: last, by: interval) {
n += 1
}
We can also use while loop as alternative way
while first <= last {
first += interval
}
for _ in 0.stride(to: last, by: interval)
{
n += 1
}
I have updated Xcode (7.3) and there are a lot of changes; C-like for expressions will be deprecated. For a simple example,
for var i = 0; i <= array.count - 1; i++
{
//something with array[i]
}
How do I write this clear and simple C-like for-loop to be compliant with the new changes?
for var i = 0, j = 1; i <= array.count - 2 && j <= array.count - 1; i++, j++
{
//something with array[i] and array[j]
}
Update.
One more variant
for var i = 0; i <= <array.count - 1; i++
{
for var j = i + 1; j <= array.count - 1; j++
{
//something with array[i] and array[j]
}
}
And more ...
for var i = 0, j = 1, g = 2; i <= array.count - 3 && j <= array.count - 2 && g <= array.count - 1; i++, j++, g++
{
//something with array[i] and array[j] and array[g]
}
Update2 After several suggestions for me while loop is preferable universal substitution for all cases more complicated than the simple example of C-like for-loop (suitable for for in expression). No need every time to search for new approach.
For instance: Instead of
for var i = 0; i <= <array.count - 1; i++
{
for var j = i + 1; j <= array.count - 1; j++
{
//something with array[i] and array[j]
}
}
I can use
var i = 0
while i < array.count
{
var j = i + 1
while j < array.count
{
//something with array[i] and array[j]
j += 1
}
i += 1
}
charl's (old) answer will crash. You want 0..<array.count:
for index in 0..<array.count {
// ...
}
If you want something like your i/j loop you can use stride and get i's successor:
for i in 0.stride(through: array.count, by: 1) {
let j = i.successor()
// ...
}
Just make sure to check i.successor() in case you go out of bounds.
for var i = 0; i <= array.count - 1; i++ {
//something with array[i]
}
Here you don't need the element index at all, so you can simply
enumerate the array elements:
for elem in array {
// Do something with elem ...
}
for var i = 0, j = 1; i <= array.count - 2 && j <= array.count - 1; i++, j++ {
//something with array[i] and array[j]
}
To iterate over pairs of adjacent elements, use zip()
and dropFirst():
for (x, y) in zip(array, array.dropFirst()) {
// Do something with x and y ...
print(x, y)
}
Output:
1 2
2 3
3 4
4 5
For other distances, use dropFirst(n):
for (x, y) in zip(array, array.dropFirst(3)) {
// Do something with x and y ...
print(x, y)
}
Output:
1 4
2 5
There are probably many solutions to do
for var i = 0; i <= <array.count - 1; i++ {
for var j = i + 1; j <= array.count - 1; j++ {
//something with array[i] and array[j]
}
}
without a C-style for-loop, here is one:
for (index, x) in array.enumerate() {
for y in array.dropFirst(index + 1) {
print(x, y)
}
}
If you want to do something with subsequent pairs there are many other ways to do it.
Something like this would work...
var previousItem = array.first
for index in 1..<array.count {
let currentItem = array[index]
// do something with current and previous items
previousItem = currentItem
}
for (i, j) in zip(array.dropLast(), array.dropFirst())
{
// something
}
What you're really doing here is enumerating two parallel sequences. So, create those sequences and use zip to turn them into a single sequence.
Do enumeration
let suits = ["♠︎", "♥︎", "♣︎", "♦︎"]
for (i, suite) in suits.enumerate() {
// ...
}
or to compare neighbors
import Foundation
let suits = ["♠︎", "♥︎", "♣︎", "♦︎"]
for (i, suite1) in suits.enumerate() {
let j = i.successor()
if j < suits.count {
let suite2 = suits[j]
// ...
}
}
or zipping and enumerating
let suits = ["♠︎", "♥︎", "♣︎", "♦︎"]
let combination = zip(suits, suits.dropFirst())
for (i, (s1,s2)) in combination.enumerate() {
print("\(i): \(s1) \(s2)")
}
result
0: ♠︎ ♥︎
1: ♥︎ ♣︎
2: ♣︎ ♦︎
Worst case, you can convert it to a while loop.
var i = 0
var j = 1
while i <= array.count -2 && j <= array.count - 1 {
// something
i += 1
j += 1
}
-- EDIT --
Because you said, "while loop is preferable universal substitution for all cases more complicated than the simple example of C-like for-loop"... I feel the need to expand on my answer. I don't want to be responsible for a bunch of bad code...
In most cases, there is a simple for-in loop that can handle the situation:
for item in array {
// do something with item
}
for (item1, item2) in zip(array, array[1 ..< array.count]) {
// do something with item1 and item2
}
for (index, item1) in array.enumerate() {
for item2 in array[index + 1 ..< array.count] {
// do soemthing with item1 and item2
}
}
For your last case, you might be justified using a for look, but that is an extremely rare edge case.
Don't litter your code with for loops.
to compare neighbouring elements from the same array you can use
let arr = [1,2,2,5,2,2,3,3]
arr.reduce(nil) { (i, j)->Int? in
if let i = i {
print(i,"==",j,"is",i == j)
}
return j
}
it prints
1 == 2 is false
2 == 2 is true
2 == 5 is false
5 == 2 is false
2 == 2 is true
2 == 3 is false
3 == 3 is true
more 'generic' approach without using subscript but separate generators
let arr1 = [1,2,3,4,5,6,7,8,9,0]
var g1 = arr1.generate()
var g2 = (arr1.dropFirst(5) as AnySequence).generate()
var g3 = (arr1.dropFirst(6) as AnySequence).generate()
while true {
if let a1 = g1.next(),
let a2 = g2.next(),
let a3 = g3.next() {
print(a1,a2,a3)
} else {
break
}
}
/* prints
1 6 7
2 7 8
3 8 9
4 9 0
*/
I have tried to update a little function to Swift 2.1. The original working code was:
import func Darwin.sqrt
func sqrt(x:Int) -> Int { return Int(sqrt(Double(x))) }
func sigma(n: Int) -> Int {
// adding up proper divisors from 1 to sqrt(n) by trial divison
if n == 1 { return 0 } // definition of aliquot sum
var result = 1
let root = sqrt(n)
for var div = 2; div <= root; ++div {
if n % div == 0 {
result += div + n/div
}
}
if root*root == n { result -= root }
return (result)
}
print(sigma(10))
print(sigma(3))
After updating the for loop I get a runtime error for the last line. Any idea why that happens?
import func Darwin.sqrt
func sqrt(x:Int) -> Int { return Int(sqrt(Double(x))) }
func sigma(n: Int) -> Int {
// adding up proper divisors from 1 to sqrt(n) by trial divison
if n == 1 { return 0 } // definition of aliquot sum
var result = 1
let root = sqrt(n)
for div in 2...root where n % div == 0 {
result += div + n/div
}
if root*root == n { result -= root }
return (result)
}
print(sigma(10))
print(sigma(3)) //<- run time error with for in loop
When you pass 3 to sigma, your range 2...root becomes invalid, because the left side, the root, is less than the right side, 2.
The closed range operator (a...b) defines a range that runs from a to b, and includes the values a and b. The value of a must not be greater than b.
root is assigned sqrt(n), which means that in order for the 2...root range to remain valid, n must be above 22.
You can fix by supplying a lower limit for the right side, i.e.
for div in 2...max(root,2) where n % div == 0 {
...
}
However, at this point your solution with the regular for loop is more readable.