Skip to index in for-in loop - swift

Let's say I have a for-in loop like this:
for index in 1...5 {
}
And let's say that I find that, at index 2, I want to skip to index 4 due to some condition. The following does not work:
for index in 1...5 {
if index == 2 {
index = 4
}
}
Because it gives me the following error:
Cannot assign to value: 'index' is a 'let' constant
How can I modify the position of the index to skip to index 4?

In a for loop, you cannot jump the index in real time - that is, if you discover once the loop has started that you need to skip an iteration, you can't. But you can duck out of an iteration with continue. So for example:
var skip = 0
for i in 1...5 {
if i < skip { continue }
print(i)
if i == 2 { skip = 4}
}
In a situation like this, however, you might be happier with a while loop.
var i = 1
while i <= 5 {
print(i)
i += 1
if i == 3 { i = 4 }
}
Another possibility is to unroll the original for loop into a while loop:
var r = (1...5).makeIterator()
while let i = r.next() {
print(i)
if i == 2 { r.next() }
}
All of those are ways of printing 1,2,4,5.

Related

Swift - Find number that is a multiple of all numbers 1...20

I am working on Euler problem 5 which is:
2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
I am having trouble with my nested loops. I have a for loop within in a while loop. My logic is I
check a number (currentNumber) against 1-20 (i), if currentNumber is not a multiple of i (checked using modular arithmatic)
then it breaks out of that loop and trys the next largest number.
My issue is I cannot figure out how to jump out of only my inner loop and not my outer loop. Here is my code:
class Five {
init() {
var currentNumber = 1
while true {
for i in 1...20 {
if currentNumber % i != 0 {
currentNumber += 1
continue
}
}
break
}
print("the smallest positive number that is evenly divisible " +
"by all of the numbers from 1 to 20 is \(currentNumber)")
}
}
You already got a good and correct answer. Just as an add-on, for the
sake of completeness:
An alternative to labeled continue statements is to move the inner loop into a separate function from which you can “early return”:
func isDivisibleBy1To20(_ number: Int) -> Bool {
for j in 2...20 {
if number % j != 0 {
return false
}
}
return true
}
var currentNumber = 1
while !isDivisibleBy1To20(currentNumber) {
currentNumber += 1
}
print("solution:", currentNumber)
Using functional methods this can be simplified to
func isDivisibleBy1To20(_ number: Int) -> Bool {
return !(2...20).contains(where: { number % $0 != 0 })
}
let solution = (1...).first(where: isDivisibleBy1To20)!
print("solution:", solution)
(Remark: There are other, much faster methods to solve this problem.)

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
}

Prime Numbers Swift 3

After hours of Googling, I'm still at a standstill. I would appreciate if someone would point out the error in my formula or coding choice. Please keep in mind I'm new to Swift. I'm not used to non C-style for loops.
if textField.text != "" {
input = Double(textField.text!)! // parse input
// return if number less than 2 entered
if input < 2 {
resultLabel.text = "Enter a number greater than or equal to 2."
return;
}
// get square root of input and parse to int
inputSquared = Int(sqrt(input));
// loop from 2 to input iterating by 1
for i in stride(from: 2, through: input, by: 1) {
if inputSquared % Int(i) == 0 {
resultLabel.text = "\(Int(input)) is not a prime number."
}
else {
resultLabel.text = "\(Int(input)) is a prime number!"
}
}
}
I didn't know the formula on how to find a prime number. After looking up multiple formulas I have sorta settled on this one. Every result is a prime number, however. So my if condition is wrong. I just don't know how to fix it.
Check my algorithm.It works.But I'm not sure this is an effective algorithm for prime number
var input:Int = 30
var isPrime:Bool = true
if(input == 2){
print("Input value 2 is prim number")
}
else if(input < 2){
print("Input value must greater than 2")
}
else{
for i in 2...input-1{
if((input%i) == 0){
isPrime = false
break;
}
}
if(isPrime){
print("Your Input Value \(input) is Prime!")
}
}
A couple of solutions that work have been posted, but none of them explain why yours doesn't. Some of the comments get close, however.
Your basic problem is that you take the square root of input, then iterate from 2 to the input checking if the integer part of the square root is divisible by i. You got that the wrong way round. You need to iterate from 2 to the square root and check that the input is divisible by i. If it is, you stop because input is not prime. If you get to the end without finding a divisor, you have a prime.
try this code in playground you will get this better idea and try to use playground when you try the swift as you are not familiar with swift playground is best.
let input = 13 // add your code that take value from textfield
var prime = 1
// throw error less than 2 entered
if input < 2 {
assertionFailure("number should be 2 or greater")
}
// loop from 2 to input iterating by 1
for i in stride(from: 2, to: input, by: 1) {
if input % i == 0{
prime = 0
}
}
if prime == 1 {
print("\(input) number is prime")
} else {
print("\(input) number is not prime")
}

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/

more elegant code for for if in swift

I got a simple code which works and which I am programming in and old fashioned way and I am sure there is a more elegant way of doing this in swift. Here is the code:
var cardsInCompartment1:Int = 0
var cardsInCompartment2:Int = 0
for card in cards{
if card.compartment == 1{
cardsInCompartment1 += 1
print(cardsInCompartment1)
}
if card.compartment == 2{
cardsInCompartment2 += 1
print(cardsInCompartment2)
}
}
I basically got cards in different compartments and now I want to count how many cards are in each compartment.
How about using filter to select the cards you want? Then you can just count them:
let cardsInCompartment1 = cards.filter { $0.compartment == 1 }.count
let cardsInCompartment2 = cards.filter { $0.compartment == 2 }.count
If you have a bunch of compartments, you could store the counts in a dictionary:
var compartmentCounts = [Int:Int]()
cards.forEach {
compartmentCounts[$0.compartment] = (compartmentCounts[$0.compartment] ?? 0) + 1
}
In this case, the key would be the compartment#, and the value would be the card count. Something like [1: 32, 2: 42] if there are 32 and 42 cards in each respective compartment.
Try this:
var cardsInCompartment1:Int = 0
var cardsInCompartment2:Int = 0
for card in cards {
(card.compartment == 1) ? (cardsInCompartment1 += 1) : (cardsInCompartment2 += 1)
}
I think you should store the cardsInCompartment as arrays:
var cardsInCompartment = [0, 0] // you can add more to this array
Then you can just loop through the cards and add the values to the array elements:
for card in cards {
cardsInCompartment[card.compartment - 1] += 1
print(cardsInCompartment[card.compartment - 1])
}
What about a switch statement? Something like this?
var card:Int = 1
var CardsInCompartment:Int = 0
switch (card) {
case 1:
CardsInCompartment += 1
print("CardsInCompartment \(CardsInCompartment)")
case 2:
CardsInCompartment += 2
print("CardsInCompartment \(CardsInCompartment)")
default:
}
Or, use an Array to keep your counts:
var counts = [ 0, 0, 0 ] // create an array of integers, where the Ints in the array represent the count of cards in each compartment
cards.forEach { counts[ $0.compartment ] += 1 } // for each card, increment the count in array corresponding to the compartment of the card. (if card.compartment == 1, increment counts[1], and so on
print("cards in compartment 1 \(counts[1])")
print("cards in compartment 2 \(counts[2])")
(This assumes your only compartments are integers 1 and 2)
I like Aaron Brager's idea which counts values into dictionary. I am using reduce to eliminate mutable dictionary outside the 'loop' (more functional)
let d = cards.reduce([:]) { (d, card) -> [Int:Int] in
var d = d
let s = d[card.compartment] ?? 0
d[card.compartment] = s + 1
return d
}