Compare array of tuples in swift - swift

I've declared the following for my tuple type:
public typealias Http2HeaderTableEntry = (field: String, value: String?)
func ==(lhs: [Http2HeaderTableEntry], rhs: [Http2HeaderTableEntry]) -> Bool {
guard lhs.count == rhs.count else { return false }
for (idx, element) in lhs.enumerated() {
guard element.field == rhs[idx].field && element.value == rhs[idx].value else {
return false
}
}
return true
}
But now when I try and use it in an assertion, like XCTAssertEqual(var1, var2) I'm getting a compiler error:
Cannot invoke 'XCTAssertEqual' with an argument list of type '([Http2HeaderTableEntry], [Http2HeaderTableEntry])'
What do I need to do in order to be able to compare two arrays of tuples in Swift 4?

Since tuples can't have conformances yet, there's not really a way to implement this in any general way at this point.
Reference here

Related

Use 'case' pattern matching to directly return result

This is my code:
enum ServerResponse {
case ok, error(Error), rawError(String), resend
func isOk(response: ServerResponse) -> Bool {
case ServerResponse.ok = response
}
}
It doesn't compile with the following error:
'case' label can only appear inside a 'switch' statement
That's strange, since this is allowed:
func isOk(response: ServerResponse) -> Bool {
if case ServerResponse.ok = response {
return true
}
return false
}
But as we can see, it costs my extra lines of codes. I expect it to work since in Swift, only booleans are allowed. The docs say:
The value of any condition in an if statement must be of type Bool or
a type bridged to Bool
This means that this line should evaluate to a boolean, since above code compiles and the line of code is the condition inside an if statement:
case ServerResponse.ok = response
Why can't I use it to directly return a boolean inside a method (first code in the question)? Is there any oneliner that checks if a given enum property is a given enum case?
You simply need to make your enum conform to Equatable, then you don't even need the case, you can simply use the == to check if your enum variable is of a concrete case.
enum ServerResponse {
case ok, error(Error), rawError(String), resend
func isOk(response: ServerResponse) -> Bool {
return response == .ok
}
}
extension ServerResponse: Equatable {
static func == (lhs: ServerResponse, rhs: ServerResponse) -> Bool {
switch (lhs, rhs) {
case ( .ok, .ok):
return true
case (.resend, .resend):
return true
case (.rawError(let string), .rawError(let otherString)):
return string == otherString
case (.error(_), .error(_)):
return true
default:
return false
}
}
}
Unrelated to your question, but defining isOk as an instance method and making it accept an input argument doesn't make sense. Either don't pass in response and simply use self == .ok or make the function a type method and then pass in the value.
Instance method:
func isOk() -> Bool {
return self == .ok
}
Then call it like: ServerResponse.ok.isOk()
Type method:
static func isOk(response: ServerResponse) -> Bool {
return response == .ok
}
Then call it like: ServerResponse.isOk(response: .resend)

Optional extension for any types

I want to write Optional extension for any types.
My code for integer:
extension Optional where Wrapped == Int {
func ifNil<T>(default: T) -> T {
if self != nil {
return self as! T
}
return default
}
}
var tempInt: Int?
tempInt.ifNil(default: 2) // returns 2
tempInt = 5
tempInt.ifNil(default: 2) // returns 5
It works but it is Optional(Int) extension (Optional where Wrapped == Int), I want to use this extension for any types like Date, String, Double etc.
What are your suggestions?
The answer to your basic question is to just remove the where clause:
extension Optional {
// ... the rest is the same
func isNil<T>(value: T) -> T {
if self != nil {
return self as! T
}
return value
}
}
Now it applies to all Optionals.
But this code is quite broken. It crashes if T is not the same as Wrapped. So you would really mean a non-generic function that works on Wrapped:
extension Optional {
func isNil(value: Wrapped) -> Wrapped {
if self != nil {
return self! // `as!` is unnecessary
}
return value
}
}
But this is just an elaborate way of saying ?? (as matt points out)
extension Optional {
func isNil(value: Wrapped) -> Wrapped { self ?? value }
}
Except that ?? is much more powerful. It includes an autoclosure that avoids evaluating the default value unless it's actually used, and which can throw. It's also much more idiomatic Swift in most cases. You can find the source on github.
public func ?? <T>(optional: T?, defaultValue: #autoclosure () throws -> T)
rethrows -> T {
switch optional {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
But I can imagine cases where you might a method-based solution (they're weird, but maybe there are such cases). You can get that by just rewriting it as a method:
extension Optional {
public func value(or defaultValue: #autoclosure () throws -> Wrapped) rethrows -> Wrapped {
switch self {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
}
tempInt.value(or: 2)
Optional is already a generic. It already takes any type as its parameterized type. Its parameterized already has a name: Wrapped. Just say Wrapped instead of T. Your T is Wrapped.
extension Optional {
func isNil<Wrapped>(value: Wrapped) -> Wrapped {
if self != nil {
return self as! Wrapped
}
return value
}
}
If you really prefer T for some reason, use a type alias. It's only a name:
extension Optional {
typealias T = Wrapped
func isNil<T>(value: T) -> T {
if self != nil {
return self as! T
}
return value
}
}
But in any case your extension is completely unnecessary because this is what the nil-coalescing operator ?? already does.
var tempInt: Int?
tempInt ?? 2 /// returns 2
tempInt = 5
tempInt ?? 2 /// returns 5

swift affect value to inout generic variable

I want to simplify this piece of code with a T variable but could not succeed in compiling it. Hope could you give me the way.
here is the "duplicate" code I want to rewrite :
func getIntegerValue (listValues: [Any], numValueToRead: Int, readValue: inout Int) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues [numValueToRead]
if type (of: value) == type(of: readValue) {
readValue = value as! Int
return true
} else {
return false
}
}
func getStringValue (listValues: [Any], numValueToRead: Int, readValue: inout String) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues [numValueToRead]
if type (of: value) == type(of: readValue) {
readValue = value as! String
return true
} else {
return false
}
}
Here is the code I wrote but do not compile :
func getValue <T> (listValues: [Any], numValueToRead: Int, readValue: inout T) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues [numValueToRead]
if type (of: value) == type(of: readValue) {
switch value {
case let integerValue as Int:
readValue = integerValue
case let stringValue as String:
readValue = stringValue
default:
return false
}
return true
} else {
return false
}
}
for those affectations I got those compilation errors :
readValue = integerValue -> 'Int' is not convertible to 'T'
readValue = stringValue -> 'String' is not convertible to 'T'
Is there a way to synthetise my two functions with a unique one using generics ?
You theoretically could make it compile by adding forced casts, since you already know that value has the type T:
case let integerValue as Int:
readValue = integerValue as! T
case let stringValue as String:
readValue = stringValue as! T
But the far better solution is to use a conditional cast (as? T) and
conditional binding (if let):
func getValue<T>(listValues: [Any], numValueToRead: Int, readValue: inout T) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues[numValueToRead]
if let tvalue = value as? T {
readValue = tvalue
return true
} else {
return false
}
}
which then works for arbitrary types, not only Int and String.
A “swiftier” way would be return an optional value (with nil
indicating "no value"). The code can then be simplified to
func getValue<T>(listValues: [Any], numValueToRead: Int) -> T? {
guard listValues.indices.contains(numValueToRead) else {
return nil
}
return listValues[numValueToRead] as? T
}
This should work:
func getValue <T> (listValues: [Any], numValueToRead: Int, readValue: inout T) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues [numValueToRead]
if type (of: value) == type(of: readValue) {
if let genericValue = value as? T {
readValue = genericValue
return true
}
return false
} else {
return false
}
}
At first sight, the function is wrongly named. You cannot call function getValue when it returns bool... I would call it transform or modify or something other than get value, because you are NOT getting value.
I think this method suits better your needs, not tested tought it should work.
func transformValue<T>(from listValues: [Any], numValueToRead: Int, readValue: inout T?) throws -> Bool {
// Guard suits better this case...
guard numValueToRead > 0 || numValueToRead < listValues.count else { return false }
let value = listValues[numValueToRead]
if type (of: value) == type(of: readValue) {
guard let value = value as? T else {
throw NSError(
domain: "Smth",
code: 1,
userInfo: ["Description": "Failed to cast to generic type T"]
)
}
readValue = value as? T
return true
}
return false // No need to call else...
}
Explenation: Returning optional generic type T is much safer. You try to cast it, you fail and you throw error that something went wrong. In my opinion saving force casts with throwing errors is much more safer approach, you know what went wrong and so.
As #MartinR pointed out, returning a nil value instead of an inout+Bool combination gives the same results, but with less, and more readable code. This is the path Swift also took when importing most of the NSError ** methods from Objective-C (i.e. dropped the last parameter, imported them as throwable functions).
These being said, another approach would be to add an extension over Array for extracting the value:
extension Array {
subscript<T>(_ index: Int, as type: T.Type) -> T? {
guard 0..<count ~= index else { return nil }
return self[index] as? T
}
}
let arr: [Any] = [1, "two", 3, "four"]
arr[1, as: String.self] // two
arr[2, as: String.self] // nil

How can two generic linked list in swift can be compared?

I have a generic linked list and I can check if two linked list are equal if each of the node value are same and are in order.
I have a function which divides linked list in two part and later I want to check two list has same value in it's node.
func divideList(atIndex index:Int) -> (first: LLGeneric<T>?,second: LLGeneric<T>?)
I looking it for my use case where I can check palindrome in linked list after dividing and then comparing ( after reversing one list).
Note: my linked list node is generic something like
class LLGenericNode<T> {
var value: T
var next: LLGenericNode?
weak var previous: LLGenericNode?
init(_ value: T) {
self.value = value
}
}
In order to compare values you have to require that T is Equatable:
class LLGenericNode<T: Equatable> {
// ...
}
Then you can implement == by comparing the values first.
If the values are equal, the list tails are compared recursively.
extension LLGenericNode: Equatable {
static func ==(lhs: LLGenericNode<T>, rhs: LLGenericNode<T>) -> Bool {
if lhs.value != rhs.value {
return false
}
switch (lhs.next, rhs.next) {
case (nil, nil):
// Both tails are == nil:
return true
case let (lvalue?, rvalue?):
// Both tails are != nil:
return lvalue == rvalue // Recursive call
default:
// One tails is nil and the other isn't:
return false
}
}
}
One-liner solution: It should be enough to define a generic T: Equatable, making sure on overloading the == operator, you compare the current values and the next nodes.
Note that with lhs.next == rhs.next you'll cover both recursion and nullability in one shot:
class Node <T: Equatable>: Equatable {
static func == (lhs: Node, rhs: Node) -> Bool {
lhs.value == rhs.value && lhs.next == rhs.next
}
}

Comparing objects in an Array extension causing error in Swift

I'm trying to build an extension that adds some of the convenience functionality of NSArray/NSMutableArray to the Swift Array class, and I'm trying to add this function:
func indexOfObject(object:AnyObject) -> Int? {
if self.count > 0 {
for (idx, objectToCompare) in enumerate(self) {
if object == objectToCompare {
return idx
}
}
}
return nil
}
But unfortunately, this line:
if object == objectToCompare {
Is giving the error:
could not find an overload for '==' that accepts the supplied arguments
Question
What am I doing wrong to cause this error?
Example
extension Array {
func indexOfObject(object:AnyObject) -> Int? {
if self.count > 0 {
for (idx, objectToCompare) in enumerate(self) {
if object == objectToCompare {
return idx
}
}
}
return nil
}
}
Actually there is no need to implement indexOfObject:; there is a global function find(array, element) already.
You can always create an extension that uses NSArray's indexOfObject, e.g:
extension Array {
func indexOfObject(object:AnyObject) -> Int? {
return (self as NSArray).indexOfObject(object)
}
}
You can specify that your array items can be compared with the <T : Equatable> constraint, then you can cast your object into T and compare them, e.g:
extension Array {
func indexOfObject<T : Equatable>(o:T) -> Int? {
if self.count > 0 {
for (idx, objectToCompare) in enumerate(self) {
let to = objectToCompare as T
if o == to {
return idx
}
}
}
return nil
}
}
My guess is that you have to do something like this:
func indexOfObject<T: Equatable>(object: T) -> Int? {
and so on.
Here's a relevant example from Apple's "The Swift Programming Language" in the "Generics" section:
func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
The key idea here is that both value and valueToFind must of a type that is guaranteed to have the == operator implemented/overloaded. The <T: Equatable> is a generic that allows only objects of a type that are, well, equatable.
In your case, we would need to ensure that the array itself is composed only of objects that are equatable. The Array is declared as a struct with a generic <T> that does not require it to be equatable, however. I don't know whether it is possible to use extensions to change what kind of types an array can be composed of. I've tried some variations on the syntax and haven't found a way.
You can extract the compare part to another helper function, for example
extension Array {
func indexOfObject(object: T, equal: (T, T) -> Bool) -> Int? {
if self.count > 0 {
for (idx, objectToCompare) in enumerate(self) {
if equal(object, objectToCompare) {
return idx
}
}
}
return nil
}
}
let arr = [1, 2, 3]
arr.indexOfObject(3, ==) // which returns {Some 2}
You were close. Here's a working extension:
extension Array {
func indexOfObject<T: Equatable>(object:T) -> Int? {
if self.count > 0 {
for (idx, objectToCompare) in enumerate(self) {
if object == objectToCompare as T {
return idx
}
}
}
return nil
}
}
Swift had no way of knowing if object or objectToCompare were equatable. By adding generic information to the method, we're then in business.