Swift String overload behavior of '>' - ios

I have a playground:
let astr = "A"
let bstr = "a"
astr > bstr
"A" > "a"
Output:
false for the first use of > and an error for the second one:
Playground execution failed: :69:5: error: ambiguous use of operator '>'
"A" > "a"
^
Foundation.>:1:6: note: found this candidate
func >(lhs: String, rhs: NSString) -> Bool
^
Foundation.>:1:6: note: found this candidate
func >(lhs: NSString, rhs: String) -> Bool
This is the drill down of the real problem I am having:
var team = ["Jane","Kate","George","Zulma"]
let sortedteam = team.sorted({ $0 > $1 })
This is giving me the same error.

You can try to use the global sorted function instead, which doesn't have this issue:
var team = ["Jane","Kate","George","Zulma"]
let sortedteam = sorted(team, { $0 > $1 })
Alternatively you could remove some of the conciseness of the closure, so the compiler knows what types it's comparing.
var team = ["Jane","Kate","George","Zulma"]
let sortedteam = team.sorted({ (s1: String, s2: String) in s1 > s2 })

Related

Comparing two Doubles in Swift: "Type of expression is ambiguous without more context"

I have a function that must check if a value (realOperand) is bigger than other value (realValue). These values are numeric, but they come in string, and I parse them to Double:
return Double(realOperand) > Double(realValue)
I can't understand why, but that line is giving this error:
Type of expression is ambiguous without more context
The function
Double.init(_ string: String) returns an Optional (Type Double?).
It would be like you wrote this code:
var a: Double? = nil
var b: Double? = 7
if a > b {
print("A is greater")
}
Is nil greater than or less than 7? It's undefined. Optionals are not Comparable.
You need to decide what to do if either or both strings can't be converted to Double:
guard let operand = Double(realOperand),
value = Double(realValue) else {
// Crash on purpose. Not a great option for user-entered Strings!
fatalError("Could not convert strings to Doubles")
}
return operand > value
You can override the operator for comparing. Optional value.
As explained more in here you can not compare optional values.
func > <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
if let lhs = lhs, let rhs = rhs {
return lhs > rhs
} else {
return false
}
}

Using higher order functions in swift

I am learning swift coming from a Haskell background, I would like to translate this bit into swift:
match :: Int -> Bool
match = (>) 3
hasMatch :: (Int -> Bool) -> [Int] -> [Int]
hasMatch pred ns = filter pred ns
hasMatch match [1..5] = [4,5]
Silly example I know. This is what I have with swift:
func hasMatch(pred : (Int) -> Bool, ns : [Int]) -> [Int]{
return ns.filter{n in pred(n:n)}
}
func match(n: Int) -> Bool{
return n > 3
}
let os = hasMatch(pred : match, ns: [1,2,3,4,5])
Which does not compile. This is the error message:
let os = hasMatch(pred : match, ns: [1,2,3,4,5])
./hello-swift.swift:48:28: error: extraneous argument label 'n:' in call
return ns.filter{n in pred(n:n)}
^~~
./hello-swift.swift:48:24: error: closure use of non-escaping parameter 'pred' may allow it to escape
return ns.filter{n in pred(n:n)}
^
./hello-swift.swift:47:15: note: parameter 'pred' is implicitly non-escaping
func hasMatch(pred : (Int) -> Bool, ns : [Int]) -> [Int]{
^
#escaping
I have two questions:
I have pred(n:n) but this assumes that pred names its input as n, which does not make sense. Do all functions have to have named inputs?
How would I change to the code so that it compiles
func hasMatch(pred: (Int) -> Bool, ns: [Int]) -> [Int] {
return ns.filter { n in pred(n) }
}
You don't need parameter names if the function is a closure.
#escaping is a keyword in swift which tells the compiler that the passed in function will escape the current scope, so it needs to retain/release the passed in arguments (Swift, like objective-c, uses retain counting for memory management)
However, you don't need it in this case - that error was a red herring thrown by the compiler because it couldn't compile the line with filter in, so it didn't know whether you needed to escape or not. Looks like it plays things safe :)
As soon as you remove the n: and it can work out which filter you are calling, it knows that because filter doesn't need an #escaping closure, your method doesn't either so that error goes away.
func mapedData(){
let bookData = ["book1":120, "book2": 150]
let mapedData = bookData.map({(key,value) in return value + 40 })
print(mapedData)
}
// [160, 190]
func filterData()
{
let bookData = ["book1":127, "book2": 150 ,"book3": 289 ,"book4": 190, "book5": 950 ]
let filterData = bookData.filter({(key,value) in return value < 200})
print(filterData)
}
// ["book2": 150, "book4": 190, "book1": 127]
func reducedData()
{
let data = [1,2,3,4,5,6,7,8,9,10]
let reducedData = data.reduce(0, { sum , number in return sum + number })
print(reducedData)
}
//55
func compactData(){
let data = [1,nil,3,4,5,6,7,nil,9,10]
let cMap = data.compactMap({return $0})
print(cMap)
}
// [1, 3, 4, 5, 6, 7, 9, 10]
func flatMappedData(){
let data = ["sachin"]
let characters = data.flatMap({return $0})
print(characters)
}
// ["s", "a", "c", "h", "i", "n"]

Cannot invoke 'split' with an argument list of type '(String, (String) -> Bool)'. Swift 2

I am currently facing the following problem with a program that I am using to learn Swift and OAuth with: https://github.com/soundcloud/iOSOAuthDemo.
The error is as follows:
Cannot invoke 'split' with an argument list of type '(String, (String) -> Bool)'
with this snippet:
private func parameterValue(name: String, fragment: String) -> String? {
let pairs = split(fragment) { $0 == "&" }.filter({ pair in pair.hasPrefix(name + "=") })
if pairs.count > 0 {
return split(pairs[0]) { $0 == "=" }[1]
} else {
return nil
}
}
The guidance is:
Expected an argument list of type '(S, maxSplit: Int, allowEmptySlices: Bool, isSeparator: #noescape (S.Generator.Element) -> R)'
Is there anyone who may be help me to remove this error, as I am new to Swift and Swift 2.0?
Thanks In Advance,
The main idea with this duplicate link was to show you that in Swift 2 String is not a collection anymore, you have to use the String's characters property (and split is not a global function anymore). You also have to make some types back to String. Example:
private func parameterValue(name: String, fragment: String) -> String? {
let pairs = fragment.characters.split { $0 == "&" }.filter({ pair in String(pair).hasPrefix(name + "=") })
if pairs.count > 0 {
let subseq = pairs[0].split { $0 == "=" }.map { String($0) }
return subseq[1]
}
return nil
}
parameterValue("mike", fragment: "&mike=test") // "test"
Note that instead you could use the String's componentsSeparatedByString method to make your function look a bit simpler:
private func parameterValue(name: String, fragment: String) -> String? {
let pairs = fragment.componentsSeparatedByString("&").filter { $0.hasPrefix(name + "=") }
if !pairs.isEmpty {
return pairs[0].componentsSeparatedByString("=")[1]
}
return nil
}
parameterValue("mike", fragment: "&mike=test") // "test"

Define tuple error: expected ',' seperator [duplicate]

I'm developing an iOS application in Swift.
When I updated the Xcode to 7.0, I'm getting error in swiftyJSON.
static func fromObject(object: AnyObject) -> JSONValue? {
switch object {
case let value as NSString:
return JSONValue.JSONString(value as String)
case let value as NSNumber:
return JSONValue.JSONNumber(value)
case let value as NSNull:
return JSONValue.JSONNull
case let value as NSDictionary:
var jsonObject: [String:JSONValue] = [:]
for (k:AnyObject, v:AnyObject) in value {// **THIS LINE- error: "Definition conflicts with previous value"**
if let k = k as? NSString {
if let v = JSONValue.fromObject(v) {
jsonObject[k] = v
} else {
return nil
}
}
}
What's the problem? Can you help, please?
for (k:AnyObject, v:AnyObject) in value { .. }
must be written in Swift 2 as
for (k, v) : (AnyObject, AnyObject) in value { .. }
From the Xcode 7 release notes:
Type annotations are no longer allowed in patterns and are considered
part of the outlying declaration. This means that code previously
written as:
var (a : Int, b : Float) = foo()
needs to be written as:
var (a,b) : (Int, Float) = foo()
if an explicit type annotation is needed. The former syntax was
ambiguous with tuple element labels.
But in your case the explicit annotation is actually not needed at all:
for (k, v) in value { .. }
because NSDictionary.Generator is already defined as a generator
returning (key: AnyObject, value: AnyObject) elements.

How do I use function parameter as literal for pattern matching in F#?

How do I write a match function that takes two strings and compares them with each other? Right now I just have this. The first one does not work. Is there a better way?
let matchFn ([<Literal>]matchString) (aString : string) = match aString with
matchString -> true
| _ -> false
let matchFn (matchString : string) (aString : string) = match aString with
_ when (matchString = aString) -> true
| _ -> false
In this specific case, you could of course just write aString = matchString, but I suppose you are asking about the general case. Literals are allowed only on the module level, and they must have a simple constant expression on their right side (source).
However, you can use an active pattern for cases like this. For example (from here):
let (|Equals|_|) expected actual =
if actual = expected then Some() else None
and then use it like this:
let matchFn (matchString : string) (aString : string) =
match aString with
| Equals matchString -> true
| _ -> false
You can use a guarded match:
let matchFn matchString (aString : string) = match aString with
x when x = matchString -> true
| _ -> false
or, perhaps more idiomatically:
let matchFn (matchString:string) = function
| x when x = matchString -> true
| _ -> false

Resources