Equation solver/parser - ios

I have an app that solves physics problems based on given knowns and unknowns .. but it does it the wrong way..
let's say we have this equation ( d = v * t )
We have here three variables .. the way I did it is like this
let v = 10
let t = 5
let d = nil
let result = Double()
if d == nil && v != nil && t != nil {
result = v * t
}if v == nil && d != nil && t != nil {
result = d / t
}if t == nil && v != nil && d != nil {
result = d / v
}else{
result = nil
}
print(result) // "50"
obviously it's a headache .. this is only a small equation with three vars.. what if I had 20 equations each has 5 vars.. it would be very exhausting to type.. So I'm wondering if there is a way to just type the equation and call .solve or something .. something like this
let equation = "d = v * t"
let knowns = [d:20,v:50]
let result = equation.solve(usingKnowns: knowns)
print(result) // "Optional(t = 0.4)"
Thanks in advance,
Any help would be really great

The problem here is to see what variable is unknown, supose you have X variables and you always get X-1 variables known and 1 unknown you don't really need to check if the knowns variables are != nil.
Other possibility is the one I recommend you:
func resolve(a: Double?, b: Double?, c: Double?)-> Double{
//Default value
var result: Double = 0.0
//a missing
if let b = b, let c = c{
result = b*c
}
//b missing
if let a = a, let b = b{
result = a/b
}
//c missing
if let a = a, let c = c{
result = a/c
}
return result
}
In this case you have a single call with the 3 parameters, all of them optionals, so if you try a "if let" with 2 o them simultaneously and it works, it means the other one is the unknow variable.
This is the "cleanest" solution I can think of.

Related

How to replace a word in a string if it contains any words from an array [duplicate]

This question already has answers here:
Replace multiple words from a String based on the values in an Array
(4 answers)
Closed 3 years ago.
I'd like to find and replace any word(s) in a string that match any string value in an array. I can find the matching value using .contains(where:
var playersApprovedArray = ["Monica","Zach","Chrissy"]
card.cardText = "Chrissy, do 10 jumping jacks right now!"
if playersApprovedArray.contains(where: card.cardText.contains) {
print("Found matching player in card text")
// Replace the matching word/player here with another word/player
}
But I don't know how to replace the occurrence of the matching word with another string value in the array.
Here is a simple solution that replaces one player with another:
for i in playersApprovedArray.indices {
let player = playersApprovedArray[i]
if let range = cardText.range(of: player) {
let otherIndex = (i + Int.random(in: 1..<playersApprovedArray.count)) % playersApprovedArray.count
let otherPlayer = playersApprovedArray[otherIndex]
cardText.replaceSubrange(range, with: otherPlayer)
break
}
}
You can remove the break if the sentence may contains more players.
Here is a faster solution that would replace all occurrences of any player's name by another:
let playersApprovedArray = ["Monica","Zach","Chrissy"]
let cardText = " Chrissy, do 10 jumping jacks right now! "
var result = ""
var i = cardText.startIndex
while i < cardText.endIndex {
var j = i
while j < cardText.endIndex,
CharacterSet.letters.inverted.isSuperset(of: CharacterSet(charactersIn: String(cardText[j])))
{
j = cardText.index(after: j)
}
var tempo1 = ""
if i != j { tempo1 += cardText[i..<j] }
if j < cardText.endIndex { i = j } else {
result += tempo1
break
}
while j < cardText.endIndex,
CharacterSet.letters.isSuperset(of: CharacterSet(charactersIn: String(cardText[j])))
{
j = cardText.index(after: j)
}
let tempo2 = String(cardText[i..<j])
if let index = playersApprovedArray.firstIndex(of: tempo2) {
let otherIndex = (index + Int.random(in: 1..<playersApprovedArray.count)) % playersApprovedArray.count
let otherPlayer = playersApprovedArray[otherIndex]
result += tempo1 + otherPlayer
//See comment below for possible early exit
} else {
result += tempo1 + tempo2
}
i = j
}
print(result) // Monica, do 10 jumping jacks right now!
If you're sure that there is only one player in the string, then you can exit early this way:
...
result += tempo1 + otherPlayer + cardText[j...]
break
...

Integers Larger than Int64

I'm attempting to get a user input number and find the sum of all the digits. I'm having issues with larger numbers, however, as they won't register under an Int64. Any idea as to what structures I could use to store the value? (I tried UInt64 and that didn't work very well with negatives, however, I'd prefer something larger than UInt64, anyways. I'm having a hard time implementing a UInt128 from Is there a number type with bigger capacity than u_long/UInt64 in Swift?)
import Foundation
func getInteger() -> Int64 {
var value:Int64 = 0
while true {
//we aren't doing anything with input, so we make it a constant
let input = readLine()
//ensure its not nil
if let unwrappedInput = input {
if let unwrappedInt = Int64(unwrappedInput) {
value = unwrappedInt
break
}
}
else { print("You entered a nil. Try again:") }
}
return value
}
print("Please enter an integer")
// Gets user input
var input = getInteger()
var arr = [Int] ()
var sum = 0
var negative = false
// If input is less than 0, makes it positive
if input < 0 {
input = (input * -1)
negative = true
}
if (input < 10) && (input >= 1) && (negative == true) {
var remain = (-1)*(input%10)
arr.append(Int(remain))
input = (input/10)
}
else {
var remain = (input%10)
arr.append(Int(remain))
input = (input/10)
}
}
// Adds numbers in array to find sum of digits
var i:Int = 0
var size:Int = (arr.count - 1)
while i<=size {
sum = sum + arr[i]
i = (i+1)
}
// Prints sum
print("\(sum)")
You can use a string to perform the operation you describe. Loop through each character and convert it to an integer and add to the sum. Be careful to handle errors.

If statement within function doesn't work

func endRound() {
timerLabel.isHidden = true
var label1Index = allEvents.index(of: label1.text!)
var label2Index = allEvents.index(of: label2.text!)
var label3Index = allEvents.index(of: label3.text!)
var label4Index = allEvents.index(of: label4.text!)
if (label4Index > label3Index > label2Index > label1Index) {
score = score + 1
let successImage = UIImage(named: "next_round_success")! as UIImage
nextRoundButtonOutlet.setImage(successImage, for: UIControlState.normal)
nextRoundButtonOutlet.isHidden = false
round = round + 1
} else {
let failImage = UIImage(named: "next_round_fail")! as UIImage
nextRoundButtonOutlet.setImage(failImage, for: UIControlState.normal)
nextRoundButtonOutlet.isHidden = false
round = round + 1
}
if (round == 6) {
}
}
For some reason, I recieve a:
"Value of type 'Array.Index?' not unwrapped; did you mean to use '!' or '??'"
error next to the first if statement.
When I add ! marks, as the compiler suggests, next to each variables within the if statement, I recieve a:
"Binary Operator '>' cannot be applied to operands of type 'Bool' and 'Array.Index' (aka int)"
and:
"Adjacent operators are in non-associative precedence group 'ComparisonPrecedence'"
Not sure what to do. The variables within the if statement represent the index number of the strings of the labels (just read the code and you would understand this).
Any help would be apperciated.
You have a few issues. The call to allEvents.index(of: label1.text!) returns an optional result since it is possible that text won't be found in the array. Adding the ! runs the risk of your app crashing if the text isn't found. One option would be to set a special value such as -1 in such a case.
var label1Index = allEvents.index(of: label1.text!) ?? -1
var label2Index = allEvents.index(of: label2.text!) ?? -1
var label3Index = allEvents.index(of: label3.text!) ?? -1
var label4Index = allEvents.index(of: label4.text!) ?? -1
Now for the if statement. You can't chain a bunch of > comparisons like that. You need:
if (label4Index > label3Index && label3Index > label2Index && label2Index > label1Index) {
}
As rmaddy says in his answer, you are getting a message about your indexes not being unwrapped because the string index(of:) function returns an Optional, which will be nil if the string isn't found.
As rmaddy also pointed out, your code to makes sure the strings are in the correct order is also invalid.
The code if a > b > c > d is not valid Swift. You have to rewrite that as
if a > b && b > c && c > d
Assuming that failing to find any of the strings means you want to follow the fail path, you could rewrite your code like this:
func endRound() {
var scored = false
timerLabel.isHidden = true
if let label1Index = allEvents.index(of: label1.text!),
let label2Index = allEvents.index(of: label2.text!),
let label3Index = allEvents.index(of: label3.text!),
let label4Index = allEvents.index(of: label4.text!),
label1Index > label2Index &&
label2Index > label3Index &&
label3Index > label4Index {
score = score + 1
let successImage = UIImage(named: "next_round_success")! as UIImage
nextRoundButtonOutlet.setImage(successImage, for: UIControlState.normal)
nextRoundButtonOutlet.isHidden = false
round = round + 1
} else {
let failImage = UIImage(named: "next_round_fail")! as UIImage
nextRoundButtonOutlet.setImage(failImage, for: UIControlState.normal)
nextRoundButtonOutlet.isHidden = false
round = round + 1
}
if (round == 6) {
}
}
That code should increase the score if all 4 strings are found and in the correct order. If one or more of the strings are not found, or anything is not in label1 label2 label3 label4 order, it will execute the else (fail) clause.
I think that's what you're after...

Usage of where in if let assignment in Swift

The Swift documentation at page 61 of the Swift manual hints to the possibility of using where to join an optional binding with a regular condition. Yet when I do it I have a warning suggesting me to substitute the where with a comma like in the following piece of code:
if let geocodingError = error as? NSError where geocodingError.code == 2
In Swift 3 this syntax has changed.
What was
if let x = y, a = b where a == x {
Is now
if let x = y, let a = b, a == x {
The justification is that each sub-clause of the if ... { is now an independent boolean test.
See the Xcode Release notes & the Swift Evolution proposal for more info about this change.
Example with two conditions
if let x = y, let a = b, a == x && !x.isEmpty {
In xcode 9
if let str = textField.text as String!, !str.isEmpty
{
params[key] = str
TextFieldHelper.setup(textField: textField)
}
else
{
TextFieldHelper.error(textField: textField)
}

swift 2 get integer value from unwrap variable

let g : String? = self.EKOMemberShipss[0].SUB_TYP_Price
let x:Int? = Int(g!)
self.valuePla.text = "\(x)"
Result
g String? " Optional(50)"
x Int? nil None
I just want to get x = 50
Check both the SUB_TYP_Price and the ability to be converted to Int
On success the optional is unwrapped respectively
if let g = self.EKOMemberShipss[0].SUB_TYP_Price, x = Int(g) {
self.valuePla.text = "\(x)"
}
Edit: According the screenshotSUB_TYP_Price is already String? so the downcast is not needed.
Just do something like this and it should work. (of course change the let g to whatever you want, this is just an example)
let g:String? = Optional("50")
print(g) //returns "Optional(50)"
let c = g!
print(c) //returns "50"

Resources