How to iterate backwards in a for loop with a range [duplicate] - swift

This question already has answers here:
Reverse Range in Swift
(7 answers)
Closed 4 years ago.
In the default case in this switch statement, I'm trying to iterate backwards in a for loop, there are examples of how to do this when working with Int's but I haven't found any with variables.
func arrayLeftRotation(myArray: [Int], d:Int) {
var newArray = myArray
switch d {
case 1:
let rotationValue = newArray.removeLast()
newArray.insert(rotationValue, at: 0)
default:
let upperIndex = newArray.count - 1
let lowerIndex = newArray.count - d
for i in lowerIndex...upperIndex {
let rotationValue = newArray.remove(at: i)
newArray.insert(rotationValue, at: 0)
}
}
print(newArray)
}
So I wish to count down from upperIndex to lowerIndex

You cannot do that with a for ... in ... statement. When using a for ... in ... statement, both the index variable and the range are immutable and you have no control over how the range is iterated through.
However, there are several alternatives you can use, such as while loops, strides and recursion.
Example for how to iterate over a range in descending order using a stride:
stride(from: upperIndex, through: lowerIndex, by: -1).forEach({ index in
let rotationValue = newArray.remove(at: index)
newArray.insert(rotationValue, at: 0)
})

Related

Speeding up Swift CodeFight Challenge

Per Codefighters:
Note: Write a solution with O(n) time complexity and O(1) additional space complexity, since this is what you would be asked to do during a real interview.
Given an array a that contains only numbers in the range from 1 to a.length, find the first duplicate number for which the second occurrence has the minimal index. In other words, if there are more than 1 duplicated numbers, return the number for which the second occurrence has a smaller index than the second occurrence of the other number does. If there are no such elements, return -1.
Example
For a = [2, 3, 3, 1, 5, 2], the output should be firstDuplicate(a) = 3.
There are 2 duplicates: numbers 2 and 3. The second occurrence of 3 has a smaller index than than second occurrence of 2 does, so the answer is 3.
For a = [2, 4, 3, 5, 1], the output should be firstDuplicate(a) = -1.
So here is what I came up with. It works but fails on the final test because it ran over 4000ms. I am stuck to what else I can do. Any Ideas to improve speed?
func firstDuplicate(a : [Int]) -> Int {
var duplicateIndexArray = [Int]()
for firstIndex in 0..<a.count {
for secondIndex in 0..<a.count {
if a[firstIndex] == a[secondIndex] && firstIndex != secondIndex {
print(firstIndex, secondIndex)
if !(duplicateIndexArray.contains(firstIndex)){
duplicateIndexArray.append(secondIndex)
break
}
}
}
}
// Check for duplicacy
if duplicateIndexArray.count > 0 {
print(duplicateIndexArray)
return a[duplicateIndexArray.min()!]
}
return -1
}
The O(n) time part is easy, but the O(1) additional space is a bit tricky. Usually, a hash set (or bit array in your case) can be used to check if a number occurred more than once, but that requires O(n) additional space. For O(1) additional space, we can use the source array itself as a bit array by making some of the numbers in it negative.
For example if the first number in the array is 3, then we make the number at position 3-1 negative. If one of the other numbers in the array is also 3, we can check if the number at position 3-1 is negative.
I don't have any experience with Swift, so I'll try to write a function in pseudocode:
function firstDuplicate(a)
result = -1
for i = 0 to a.count - 1
if a[abs(a[i])-1] < 0 then
result = a[i]
exit for loop
else
a[abs(a[i])-1] = -a[abs(a[i])-1]
// optional restore the negative numbers back to positive
for i = 0 to a.count - 1
if a[i] < 0 then
a[i] = -a[i]
return result
Replace this line
for secondIndex in 0..<a.count
with
for secondIndex in firstIndex..<a.count
There is no requirement of double checking
So Your Final code is
func firstDuplicate(a : [Int]) -> Int {
var duplicateIndexArray = [Int]()
for firstIndex in 0..<a.count {
for secondIndex in firstIndex..<a.count {
if a[firstIndex] == a[secondIndex] && firstIndex != secondIndex {
print(firstIndex, secondIndex)
if !(duplicateIndexArray.contains(firstIndex))
{
duplicateIndexArray.append(secondIndex)
break
}
}
}
}
// Check for duplicacy
if duplicateIndexArray.count > 0
{
print(duplicateIndexArray)
return a[duplicateIndexArray.min()!]
}
return -1
}
func firstDuplicate(input: [Int]) -> Int{
var map : [String : Int] = [:]
var result = -1
for i in 0 ..< input.count {
if map["\(input[i])"] != nil {
result = i
break
}
else {
map["\(input[i])"] = i
}
}
return result
}

for loop over odd numbers in swift

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/

Swift range operator for i = mymax; i >= 0 i-- [duplicate]

This question already has answers here:
#warning: C-style for statement is deprecated and will be removed in a future version of Swift [duplicate]
(4 answers)
Decrement index in a loop after Swift C-style loops deprecated
(5 answers)
Closed 6 years ago.
I facing problem in executing for loop in Swift 3. I can use loop for range operator ... and ..< but in may case, I want something like ..> but its not available.
How do I execute following loop in Swift 3?
var myMax = 20
for var i = myMax ; i >= 0 ; i -= 1 {
...
}
It's easy to reverse the loop. User reversed function.
Swift 3
let myMax = 20
for i in (1..<myMax).reversed() {
print(i)
}
You can also use stride as #ZaidPathan said :
This question have all answers with all versions : How to iterate for loop in reverse order in swift?
for i in (1..<20).reversed() {
print(i)
}
Hope it helps.Read More
Swift 3, You can use stride
var myMax = 20
for var i = myMax ; i > 0 ; i -= 1 {
}
//Equivalent
let myMax = 20
for value in stride(from: 20, to: 0, by: -1){
print(value)
}
var myMax = 20
for var i = myMax ; i >= 0 ; i -= 1 {
}
//Equivalent
for value in stride(from: 20, through: 0, by: -1){
print(value)
}

Swift 3 for loop with increment

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
}

Swift Range Type endIndex

If you create a var Range = 0...0, I would expect the endIndex to be zero. But in reality is 1.
var myRange: Range<Int> = 0...0
print("start Index \(myRange.startIndex) End Index \(myRange.endIndex)")
output: "start Index 0 End Index 1"
How can I question a Range instance if an Index of type Int is contained ?
The endIndex is not actually included in the Range. The Range is startIndex ..< endIndex. So, for your example, 0...0 is stored as 0..<1 which means the same thing.
For Swift 1.2 you can use the global function contains to check if an Int is contained by a Range:
var myRange: Range<Int> = 0...0
let i: Int = 1
if contains(myRange, i) {
println("yes")
} else {
println("no") // prints "no"
}
For Swift 2.0:
var myRange: Range<Int> = 0...0
let i: Int = 1
if myRange.contains(i) {
print("yes")
} else {
print("no") // prints "no"
}
Maybe you could refer to Half-Open Range Operator
var myRange: Range<Int> = 0..<0
outputs:"start Index 0 End Index 0"
The half-open range operator (a..<b) defines a range that runs from a to b, but does not include b. And the closed range operator (a...b) will finally turn to (a..<b+1)
Because Range is also a collection, you can use its minElement() and maxElement() methods, which will return the correct index, respecting the range being closed (...) or half-open (..<).
So the below code will output zeros as expected:
let range: Range<Int> = 0...0
let min = range.minElement()!
let max = range.maxElement()!
print("min=\(min), max=\(max)")
// Output: "min=0, max=0"
Note: both methods have O(elements.count) complexity which might not be suitable for some cases.