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

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.

Related

Converting Optional String to Int in Swift 4

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}

Is it possible to use the variable from an optional binding within the same conditional statement?

if let popupButton = result?.control as? NSPopUpButto {
if popupButton.numberOfItems <= 1 {
// blahblah
}
}
I want to avoid the double nested if.
if let popupButton = result?.control as? NSPopUpButton && popupButton.numberOfItems <= 1 {}
but I get the unresolved identifier compiler error if I do that.
Is there any way to make this condition on one line? Or because I'm using an optional binding, am I forced to make a nested if here?
You can do it this way:
if let popupButton = result?.control as? NSPopUpButton, popupButton.numberOfItems <= 1 {
//blahblah
}

Get All Value in Array except "x" value Swift 3

I'm new in IOS programming. I have a question, how to get all value in array except x value. Let say i have array like below :
let array : [Any] = [1,2,3,4,5,6,7,8,9,0,11,22,33,44,55,66,77,200]
how to print all value except 1 and 2.
I have read this , its using filter and i try it with playground but i still not have the right value. Any answer will helpfull for me. Thanks in advance .
I don't know why you have defined the array as [Any] so I just removed that and the array is:-
let array = [1,2,3,4,5,6,7,8,9,0,11,22,33,44,55,66,77,200]
Next you can use filter as follows:-
let filtered = array.filter { (element) -> Bool in
return element != 1 && element != 2
}
You can test this out in the playground, it will print all values except 1 & 2
You can also use some syntactical sugar for filter as follows:-
array.filter({ return $0 != 1 && $0 != 2 })
And since the closure is a trailing argument, you can also separate it from the arguments as follows:-
array.filter { return $0 != 1 && $0 != 2 }
Another way to do this would be
let filterTheseOut = [1,2]
let anotherWay = array.filter { !filterTheseOut.contains($0) }
So here you can basically add all the elements to be filtered out in a separate array
You can do it like this
let array : [Int] = [1,2,3,4,5,6,7,8,9,0,11,22,33,44,55,66,77,200]
print(array.filter { $0 != 1 && $0 != 2 } )
or if you will have more than 1 or 2 values you can put them into array
let array : [Int] = [1,2,3,4,5,6,7,8,9,0,11,22,33,44,55,66,77,200]
let unwantedValues = [1,2]
print(array.filter { unwantedValues.contains($0) == false } )
Next time please paste your code, it will be easier to tell you what you're doing wrong, then giving you ready solution.
No need for filter use this:
for i in array {
if i != 1 && i != 2 {
print i
}
}
// This will print all values except 1 and 2

Swift on array.sort - Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions

I am downgrading Swift code from Xcode 8.3.1 to Xcode 7.3.1.
The Swift compiler of Xcode 7.3.1 raises
Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
while pointing on line zeroParameterAndPaths.sort {. The code was ok in Xcode 8.3.1.
What's wrong and how to fix it?
class NewConnectingSegmentZeroParameterAndPath {
let step : Int; // 0 = main, 1 = first outline, 2 = second outline
let parameter : CGFloat;
init(step: Int, parameter: CGFloat) {
self.step = step;
self.parameter = parameter;
}
}
var zeroParameterAndPaths : [NewConnectingSegmentZeroParameterAndPath] = [];
// ... some zeroParameterAndPaths .appendContentsOf calls
zeroParameterAndPaths.sort {
return $0.parameter < $1.parameter
|| ($0.parameter == $1.parameter
&& ($0.step == 1 || ($0.step == 0 && $1.step == 2))
)
};
You have two choices. One is simply to do what the error message suggests, i.e. pulling the complex bool apart into separate pieces:
zeroParameterAndPaths.sort {
let bless = ($0.parameter < $1.parameter)
let beq = ($0.parameter == $1.parameter)
let band = ($0.step == 0 && $1.step == 2)
let bor = ($0.step == 1 || band)
let beqandbor = (beq && bor)
return (bless || beqandbor)
};
The other is to provide an explicit in line giving the param types and result type:
zeroParameterAndPaths.sort {
(a:NewConnectingSegmentZeroParameterAndPath, b:NewConnectingSegmentZeroParameterAndPath) -> Bool in
return a.parameter < b.parameter
|| (a.parameter == b.parameter
&& (a.step == 1 || (a.step == 0 && b.step == 2))
)
};
You could also make your class a little bit more helpful and make it implement the condition. The compiler is much less likely to get confused in a function body than in a closure:
class NewConnectingSegmentZeroParameterAndPath {
let step : Int; // 0 = main, 1 = first outline, 2 = second outline
let parameter : CGFloat;
init(step: Int, parameter: CGFloat) {
self.step = step;
self.parameter = parameter;
}
func orderedBefore(_ other: NewConnectingSegmentZeroParameterAndPath) -> Bool
{
return parameter < other.parameter
|| parameter == other.parameter
&& (step == 1 || step == 0 && other.step == 2)
}
}
var zeroParameterAndPaths : [NewConnectingSegmentZeroParameterAndPath] = [];
// ... some zeroParameterAndPaths .appendContentsOf calls
zeroParameterAndPaths.sort { $0.orderedBefore($1) }
Apart from the issue of the type inference engine not being able to quickly resolve such complex bool expressions, such expressions are really hard to follow. I suggest you break it down into something simpler, like so:
zeroParameterAndPaths.sort {
if $0.parameter != $1.parameter { return $0.parameter < $1.parameter ]
if $0.step == 1 { return true }
if $0.step == 0 && $1.step == 2 { return true }
return false
};
There's my attempt at it. I'm not even sure if it's correct, the original expression is pretty hard to follow.

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
}