Swift 3.0 multiple conditions in c-style for loop - swift

I understand how to write a for loop using swift syntax (using .enumerate() and .revers()), however how would I re-write (in swift) the following javascript version of for loop, considering I have multiple conditions to adhere to:
for(var j = 10; j >= 0 && array[j] > value; j--) {
array[j + 1] = array[j];
}

What about this?
for j in (0...10).reversed() {
guard array[j] > value else { break }
array[j + 1] = array[j]
}

I'm not sure that produces exactly the same result, but this is one of the approaches in Swift 3
for j in stride(from:10, through:0, by: -1) {
if array[j] <= value { break }
array[j + 1] = array[j]
}

For the sake of completion (I would personally prefer to use a for loop with a check for an early break, as others have already suggested) – in Swift 3.1 you could use Sequence's prefix(while:) method in order to get the suffix of the array's indices where the elements meet a given predicate.
var array = [2, 3, 6, 19, 20, 45, 100, 125, 7, 9, 21, 22]
let value = 6
for i in array.indices // the array's indices.
.dropLast() // exclude the last index as we'll be accessing index + 1 in the loop.
.reversed() // reversed so we can get the suffix that meets the predicate.
.prefix(while: {array[$0] > value}) // the subsequence from the start of the
{ // collection where elements meet the predicate.
array[i + 1] = array[i]
}
print(array) // [2, 3, 6, 19, 19, 20, 45, 100, 125, 7, 9, 21]
This is assuming that you're looking to begin iterating at the penultimate index of the array. If you want to start at a particular index, you can say:
for i in (0...10).reversed().prefix(while: {array[$0] > value}) {
array[i + 1] = array[i]
}
This will start at the index 10 and iterate down to 0, giving you the same behaviour to the code in your question.
It's worth noting that both of the above variants will first iterate through the reversed indices (until the predicate isn't met), and then through the array's elements. Although, in Swift 3.1, there is a version of prefix(while:) which operates on a lazy sequence – which would allow for just a single iteration through the elements until the predicate isn't met.
Until Swift 3.1, you can use the below extension to get prefix(while:) on a Collection:
extension Collection {
func prefix(while predicate: (Self.Iterator.Element) throws -> Bool) rethrows -> Self.SubSequence {
var index = startIndex
while try index < endIndex && predicate(self[index]) {
formIndex(after: &index)
}
return self[startIndex..<index]
}
}

Related

Efficient way to get a subsequence with a precondition in Swift

I have an ordered sequence of numbers, let's say something like
0, 1, 2, 3, 5, 6, 11, 12, 15, 20
Given a number N, how could I get a sequence that starts from the last number that is smaller than N? For example, if N = 7, I'd like to get back
6, 11, 12, 15, 20
Please note that this sequence will get very big and new numbers will be appended.
drop(while:) seemed like a good candidate, but in the example above it would also drop 6 so I can't use it.
For huge sorted arrays the most efficient way is binary search. It cuts the array in half until the index was found.
extension RandomAccessCollection where Element : Comparable {
func lastIndex(before value: Element) -> Index {
var slice : SubSequence = self[...]
while !slice.isEmpty {
let middle = slice.index(slice.startIndex, offsetBy: slice.count / 2)
if value < slice[middle] {
slice = slice[..<middle]
} else {
slice = slice[index(after: middle)...]
}
}
return slice.startIndex == self.startIndex ? startIndex : index(before: slice.startIndex)
}
}
let array = [0, 1, 2, 3, 5, 6, 11, 12, 15, 20]
let index = array.lastIndex(before: 7)
print(array[index...])

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
}

Multiple increments in Swift style for loops

I have the following loop in my Swift code:
for var i:Int = 0, j:Int = 0; i < rawDataOut.count; i += 4, ++j {
maskPixels[j] = rawDataOut[i + 3]
}
I'm getting two warnings in Xcode:
C-style for statement is deprecated and will be removed in a future version of Swift
'++' is deprecated: it will be removed in Swift 3
I cannot see how to rewrite this in Swift's For In Loops to take into account the two variables and the 4-stride without it getting messy. Is there a simple elegant translation?
Preconditions to answering this: looking over your example
I will assume that you intended to limit i by i < rawDataOut.count-3 rather than i < rawDataOut.count, otherwise the rawDataOut[i + 3] element access by index wouldn't make much sense w.r.t. runtime safety. Anyway, without you showing us rawDataOut, this is an assumption we shall have to make.
Hence, your original loop (including a verifiable example) looks as follows
/* example data */
var rawDataOut = Array(1...40)
var maskPixels = [Int](count: 10, repeatedValue: 0)
/* your pre-Swift 2.2/3.0 loop */
for var i: Int = 0, j: Int = 0; i < rawDataOut.count-3; i += 4, ++j {
maskPixels[j] = rawDataOut[i + 3]
}
print(maskPixels) //[4, 8, 12, 16, 20, 24, 28, 32, 36, 40]
Using for in ... where
In your specific example case, the multiple increments have a simple relation (j=4*i) so we could solve this without even making use of an explicit j iterate, e.g.
/* example data */
var rawDataOut = Array(1...40)
var maskPixels = [Int](count: 10, repeatedValue: 0)
/* your pre-Swift 2.2/3.0 loop */
for i in 0..<(rawDataOut.count-3) where i%4 == 0 {
maskPixels[i/4] = rawDataOut[i + 3]
}
print(maskPixels) // [4, 8, 12, 16, 20, 24, 28, 32, 36, 40]
but this is possibly not really of interest for the general discussion of two iterates. We move on to a 2-iterate method combining stride and enumerate.
Combining stride and enumerate
One solution is to enumerate the stride described by iterate i in your loop above, and use the enumeration index to construct the second iterate (j above). In your example, the enumerate index exactly corresponds to j, i.e.
/* example data */
var rawDataOut = Array(1...40)
var maskPixels = [Int](count: 10, repeatedValue: 0)
/* Swift >= 2.2 loop */
for (j, i) in 0.stride(to: rawDataOut.count-3, by: 4).enumerate() {
maskPixels[j] = rawDataOut[i + 3]
}
print(maskPixels) // [4, 8, 12, 16, 20, 24, 28, 32, 36, 40]
Note that in Swift 3 (as compared to 2.2), it seems as if the default implementations of stride(to:by:) and stride(through:by:) to protocol Strideable (as non-blueprinted extension methods) will be depracated, and that we're back to (as in Swift 1.2) using the global functions stride(from:to:by:) and stride(from:through:by:), see e.g. the current master branch of swift/stdlib/public/core/Stride.swift
Trickier cases: resort to while
For trickier cases, say a signature in your pre-Swift 2.2 loop as
for var i: Int = 0, j: Int = 0; i < rawDataOut.count-3; i += 4, j += i { ... }
you're probably best of simply using a while loop with one iterate associated with the loop invariant, and a trailing iterate as a free variable; whether this is considered messy or not is a matter of taste, I suppose.
var i = 0, j = 0
while i < rawDataOut.count-3 {
// ...
// increase iterates
i += 4
j += i
}
I assume the reason for removing the C-style loop is that it's, in most cases, directly covered by for in, stride etc, and for cases where these don't suffice, a good old' while, most likely, will.
In Swift 4
for index in stride(from: 0, to: 10, by: 2){
print(index)
}

Decrement index in a loop after Swift C-style loops deprecated

How would you express a decrementing indexed loop in Swift 3.0, where the syntax below is not valid any more?
for var index = 10 ; index > 0; index-=1{
print(index)
}
// 10 9 8 7 6 5 4 3 2 1
Here is an easier (and more Swifty) approach.
for i in (0 ..< 5).reversed() {
print(i) // 4,3,2,1,0
}
let array = ["a", "b", "c", "d", "e"]
for element in array.reversed() {
print(element) // e,d,c,b,a
}
array.reversed().forEach { print($0) } // e,d,c,b,a
print(Array(array.reversed())) // e,d,c,b,a
C-style loops with a fixed increment or decrement can be replaced
by stride():
for index in 10.stride(to: 0, by: -1) {
print(index)
}
// 10 9 8 7 6 5 4 3 2 1
Use stride(to: ...) or stride(through: ...) depending on whether
the last element should be included or not.
This is for Swift 2. The syntax changed (again) for Swift 3, see
this answer.
From swift 3.0, The stride(to:by:) method on Strideable has been replaced with a free function, stride(from:to:by:)
for index in stride(from: 10, to: 0, by: -1) {
print(index)
}
// You can also use stride condition like
// {Some Value}.stride(to: 0, by: -1)
// for index in 10.stride(to: 0, by: -1) { }
You can use stride method:
10.stride(through: 0, by: -1).forEach { print($0) }
or classic while loop.
If you still want to use this C-style loop, here is what you need:
let x = 10
infix operator ..> { associativity left }
func ..>(left: Int, right: Int) -> StrideTo<Int> {
return stride(from: left, to: right, by: -1)
}
for i in x..>0 {
print(i)
}

Simple Swift Fibonacci program crashing (Project Euler 2)

I am trying to solve the second problem on Project Euler. The problem is as follows:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
I think I've written a solution, but when I try to run my code it crashes my Swift playground and gives me this error message:
Playground execution aborted: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
var prev = 0
var next = 1
var num = 0
var sum = 0
for var i = 1; i < 400; i++ {
num = prev + next
if next % 2 == 0 {
sum += next
}
prev = next
next = num
}
print(sum)
The weird thing is, if I set the counter on my loop to less than 93, it works fine. Explicitly setting the variable names to Double does not help. Anyone know what's going on here?
There is nothing weird about this at all. Do you know how large the 400 fibonacci number is?
176023680645013966468226945392411250770384383304492191886725992896575345044216019675
Swift Int64 or UInt64 simply cannot handle that large of a number. The later can go up to 18446744073709551615 at max - not even close.
If you change your variables to be doubles it works but will be inaccurate:
var prev : Double = 0
var next : Double = 1
var num : Double = 0
var sum : Double = 0
will yield
2.84812298108489e+83
which is kind of close to the actual value of
1.76e+83
Luckily you do not need to get values that big. I would recommend not writing a for loop but a while loop that calculates the next fibonacci number until the break condition is met whose values do not exceed four million.
The Fibonacci numbers become very large quickly. To compute large Fibonacci numbers, you need to implement some kind of BigNum. Here is a version the makes a BigNum that is implemented internally as an array of digits. For example, 12345 is implemented internally as [1, 2, 3, 4, 5]. This makes it easy to represent arbitrarily large numbers.
Addition is implemented by making the two arrays the same size, then map is used to add the elements, finally the carryAll function restores the array to single digits.
For example 12345 + 67:
[1, 2, 3, 4, 5] + [6, 7] // numbers represented as arrays
[1, 2, 3, 4, 5] + [0, 0, 0, 6, 7] // pad the shorter array with 0's
[1, 2, 3, 10, 12] // add the arrays element-wise
[1, 2, 4, 1, 2] // perform carry operation
Here is the implementation of BigNum. It is also CustomStringConvertible which makes it possible to print the result as a String.
struct BigNum: CustomStringConvertible {
var arr = [Int]()
// Return BigNum value as a String so it can be printed
var description: String { return arr.map(String.init).joined() }
init(_ arr: [Int]) {
self.arr = carryAll(arr)
}
// Allow BigNum to be initialized with an `Int`
init(_ i: Int = 0) {
self.init([i])
}
// Perform the carry operation to restore the array to single
// digits
func carryAll(_ arr: [Int]) -> [Int] {
var result = [Int]()
var carry = 0
for val in arr.reversed() {
let total = val + carry
let digit = total % 10
carry = total / 10
result.append(digit)
}
while carry > 0 {
let digit = carry % 10
carry = carry / 10
result.append(digit)
}
return result.reversed()
}
// Enable two BigNums to be added with +
static func +(_ lhs: BigNum, _ rhs: BigNum) -> BigNum {
var arr1 = lhs.arr
var arr2 = rhs.arr
let diff = arr1.count - arr2.count
// Pad the arrays to the same length
if diff < 0 {
arr1 = Array(repeating: 0, count: -diff) + arr1
} else if diff > 0 {
arr2 = Array(repeating: 0, count: diff) + arr2
}
return BigNum(zip(arr1, arr2).map { $0 + $1 })
}
}
// This function is based upon this question:
// https://stackoverflow.com/q/52975875/1630618
func fibonacci(to n: Int) {
guard n >= 2 else { return }
var array = [BigNum(0), BigNum(1)]
for i in 2...n {
array.append(BigNum())
array[i] = array[i - 1] + array[i - 2]
print(array[i])
}
}
fibonacci(to: 400)
Output:
1
2
3
5
8
...
67235063181538321178464953103361505925388677826679492786974790147181418684399715449
108788617463475645289761992289049744844995705477812699099751202749393926359816304226
176023680645013966468226945392411250770384383304492191886725992896575345044216019675