Converting Optional String to Int in Swift 4 - swift

I'm trying to make a call from my JSON file where the variable is a string however in order to compare it I would want it to be an integer, however, whenever I try and convert it using methods on here nothing seems to be working, assuming the wrong syntax. This line essentially (pData.info?.nutriScore ?? 0) prints a score however its a string.
if let nScore = Int(pData.info?.myScore ?? 0) < 0 {
//Other Code
}

if let nutriScore = pData.info?.nutriScore, let nScore = Int(nutriScore) {
// your code here
}

You need
if let nScore = Int(pData.info?.myScore ?? "0" ) , nScore > 0 {
}

if let nScore:Int = Int(pData.info?.nutriScore ?? "0") {
if nScore < 0 {
print(nScore)
}
}

Avoid using ?? default value ,
Yes you dont have the value in your object so you are passing the default that doesnt mean default value is your Real data .
if let b = pData.info?.myScore, let nScore = Int(b) , nScore >= 0{
print(nScore)
} else {// handle negative logic}

Related

Unresolved identifier error in swift function with nested if loop

I'm currently teaching myself Swift coming from a background of Python recently and Visual Basic originally. I would describe myself as competent in those codes but a novice in Swift. I'm trying to write a function that will return a set number of digits from either the start or end of a long integer. My chosen method has been to convert the integer to a string and then use the prefix or suffix command.
Whilst I can get the function to work if it has no flow control and uses either prefix or suffix (first lot of code), when I try to write one function that does both I get an unresolved identifier error on the turnStringToInteger variable (second lot of code). I'm pretty sure this is because the variable lives within the if {} but if I declare it outside of the if loop (hashed out) this also errors. I appreciate this will have a really simple answer but how do I use the return correctly with a nested if loop?
This works...
//Function to Trim Integer (Prefix Only)
func integerTrim(integer:Int, trimLength:Int) -> Int {
var strFromInteger = String(integer)
var trimmedString = strFromInteger.prefix(trimLength)
var intFromString = Int(trimmedString) ?? 0
return intFromString
}
//Declare Input
var inputInt = 12345678910
//Call Function
var result = integerTrim(integer: inputInt, trimLength: 4)
//Print Results
print(inputInt)
print(result)
This doesn't...!
//Function to trim integer prefix or suffix
func integerTrim(integer:Int, type:String, trimLength:Int) -> Int {
var typeID = type
//var turnStringToInteger: Int
if typeID == "P" {
var turnIntegerToString = String(integer)
var trimmedString = turnIntegerToString.prefix(trimLength)
var turnStringToIngeger = Int(trimmedString) ?? 0
}
else if typeID == "S" {
var turnIntegerToString = String(integer)
var trimmedString = turnIntegerToString.suffix(trimLength)
var turnStringToIngeger = Int(trimmedString) ?? 0
}
return turnStringToInteger
}
//Declare Input
var inputInt = 53737363856453
//Call Function
var result = integerTrim(integer: inputInt, type: "P", trimLength: 4)
//Print Results
print(inputInt)
print(result)
As I am self taught I appreciate I may also not be using best practices. I really want to learn to do this properly so if I am going about all of this the wrong way to begin with I would be equally happy to hear other approaches. For example I did consider turning the integer to an array and then creating the trimmed integer from positions within this array. Would this be more elegant?
If you want to access the variable outside of the scope where it is assigned, you need to declare it in the outer scope.
If you do that without assigning it an initial value, you get an error: variable 'turnStringToInteger' used before being initialized. That happens because Swift sees a path in which turnStringToInteger never gets assigned a value (imagine what happens if "X" is passed in for type).
So your real issue is the use of String as the type for type. It would be better to use an enum that expresses exactly what you want:
enum TrimType {
case prefix, suffix
}
func integerTrim(integer: Int, type: TrimType, trimLength: Int) -> Int {
let typeID = type
var turnStringToInteger: Int
switch typeID {
case .prefix:
let turnIntegerToString = String(integer)
let trimmedString = turnIntegerToString.prefix(trimLength)
turnStringToInteger = Int(trimmedString) ?? 0
case .suffix:
let turnIntegerToString = String(integer)
let trimmedString = turnIntegerToString.suffix(trimLength)
turnStringToInteger = Int(trimmedString) ?? 0
}
return turnStringToInteger
}
Now there are only 2 possibilities for type and the switch handles both.
You call it like this:
let result = integerTrim(integer: inputInt, type: .prefix, trimLength: 4)
... after a little refactoring:
func integerTrim(integer: Int, type: TrimType, trimLength: Int) -> Int {
let turnIntegerToString = String(integer)
let trimmedString: Substring
switch type {
case .prefix:
trimmedString = turnIntegerToString.prefix(trimLength)
case .suffix:
trimmedString = turnIntegerToString.suffix(trimLength)
}
return Int(trimmedString) ?? 0
}
There's a few ways to do this. The root of the problem is your turnIntegerToString lifetime is within the braces - and the return is outside the braces.
func integerTrim(integer:Int, type:String, trimLength:Int) -> Int {
var typeID = type
var turnStringToInteger: Int = 0
// If you don't want to assign it to zero (your nil coalesce implies we can) - instead use...
// var turnStringToInteger: Int! // However - this can crash since your if statement does not cover all situations
if typeID == "P" {
var turnIntegerToString = String(integer)
var trimmedString = turnIntegerToString.prefix(trimLength)
turnStringToIngeger = Int(trimmedString) ?? 0
}
else if typeID == "S" {
var turnIntegerToString = String(integer)
var trimmedString = turnIntegerToString.suffix(trimLength)
turnStringToIngeger = Int(trimmedString) ?? 0
}
return turnStringToInteger
}

If Int is a negative value, is there a way to express it as 0?

I faced situation, which is
let IntA = IntB - IntC
let usingInt = IntA <= 0 ? 0 : IntA
But, Just not smart I felt.
Is there some cool methods??
You can use the max function for this:
let IntA = IntB - IntC
let usingInt = max(IntA, 0)
How about using the setter methods to do the same thing suggested in the other answer?
var result: Int = 0 {
didSet {
result = max(0, result)
}
}
Use this variable to store your calculation result.
result = 4 - 5
print(result) //0

swift 3 loop error (taking variable and adding it by itself)

My code does not work right now. I am trying to take names and add it by itself in the loop but the complier is giving me a error message and the code is not being printed.
let names = [Double(2),3,8] as [Any]
let count = names.count
for i in 0..<count {
print((names[i]) + names[i])
}
Because Any doesn't have + operator.
This will give you the result you expected.
If you want to add 2 values and print the result, you need to cast Any to calculatable like Double
let names = [Double(2),3,8] as [Any]
let count = names.count
for i in 0..<count {
if let value = names[i] as? Double {
print(value + value)
}
}
The use of as [Any] makes no sense. You can't add two objects of type Any which is probably what your error is about.
Simply drop it and your code works.
let names = [Double(2),3,8]
let count = names.count
for i in 0..<count {
print(names[i] + names[i])
}
Output:
4.0
6.0
16.0
Better yet:
let names = [Double(2),3,8]
for num in names {
print(num + num)
}

Swift: How to use more than one 'where' on conditional binding?

I did some google searched and the examples use " , " to use more than one where statement but it doesn't work for me. I have tried && as well.
if let movesDict = pokemonInfoDict["moves"] as? [Dictionary<String,AnyObject>] where movesDict.count > 0, movesDict["learn_type"] == "level up"{
}
if let movesDict = pokemonInfoDict["moves"] as? [Dictionary<String,AnyObject>] where movesDict.count > 0 && movesDict["learn_type"] == "level up"{
}
Any help would be greatly appreciated thanks.
You want && - you must have some other problem with your code, as this works:
let foo: Int? = 10
if let bar = foo where bar > 8 && bar % 2 == 0 {
print("It works")
}
You tried this:
if let movesDict = pokemonInfoDict["moves"] as? [Dictionary<String,AnyObject>]
where movesDict.count > 0
&& movesDict["learn_type"] == "level up"
{
// ...
}
The problem is that movesDict is a array of dictionaries, and you tried to use the string "learn_type" as the subscript of that array when you said movesDict["learn_type"], but an array subscript must be an Int.

Using guard with a non-optional value assignment

This is not a question about optional arrays, as one can see in the answers.
I like using guard because it makes your intensions clear. I've used it both for the optional version like this...
guard let c = MyOptionalArray else { return }
as well as for more traditional bounds checking on non-optionals...
guard MyArray.count > 0 else { return }
But now I'd like to use that count in following code. So I did...
guard let c = MyArray.count > 0 else { return }
which doesn't work, obviously, so I did what should...
guard let c = parts.count where c > 1 else { return }
But that says Initializer for conditional binding must have Optional type, not 'Int'. Now I understand the error, and tried a bunch of seemingly obvious changes to the format, but no go. Is there no way to use guard as an assignment on a non-optional value? This seems like something it should be able to do.
If you throw a case in there, it'll work. So as follows:
guard case let c = parts.count where c > 1 else { return }
You can initialize an optional wrapping the non-optional:
guard let count = Optional([42].count), count > 0 else {
return
}
guard let count = .some([42].count), count > 0 else {
return
}
or cast it to an optional:
guard let count = [42].count as Int?, count > 0 else {
return
}
As mentioned in other answers, guard case let also works:
guard case let count = [42].count, count > 0 else {
return
}
guard case let count = [42].count where count > 0 else {
return
}