Cannot convert return expression of type Object<String> to return type Object<Character> - swift

I am working with some piece of code found in Functional programming in Swift, but the book is not updated with Swift 2, and I am getting on error in the following code:
func insert<T: Hashable>(key: [T], trie: Trie<T>) -> Trie<T> {
if let (head, tail) = key.decompose {
if let nextTrie = trie.children[head] {
var newChildren = trie.children
newChildren[head] = insert(tail, trie: nextTrie)
return Trie(isElem: trie.isElem, children: newChildren)
} else {
var newChildren = trie.children
newChildren[head] = single(tail)
return Trie(isElem: trie.isElem, children: newChildren)
}
} else {
return Trie(isElem: true, children: trie.children)
}
}
func buildString(words: [String]) -> Trie<Character> {
return reduce(words, empty()) { trie, word in
insert([word], trie: trie)
}
}
Inside buildString I get this:
Cannot convert return expression of type Trie<String> to return type Trie<Character>
How can I fix this ?

Assuming that empty looks like this
func empty<T>() -> Trie<T> {
return Trie<T>()
}
change the buildString function to
func buildString(words: [String]) -> Trie<Character> {
return words.reduce(empty()) { trie, word in
insert(Array(word.characters), trie: trie)
}
}
Explanation
What you want in the first argument of insert is an array of Character instances which you get by calling Array(word.characters). Array(word) is the Swift 1.2 way and doesn't work in Swift 2 anymore. In addition, [word.characters] just creates an array with a single element (the string's character view) which is why it doesn't work as well.
Note that I also changed the global reduce function (Swift 1.2 way) to the instance method .reduce (Swift 2 way).

Related

Swift testing non-scalar types

I want to test my function that takes a string, a returns all the pairs of characters as an array s.t.
func pairsOfChars(_ s: String) -> [(Character,Character)] {
let strArray = Array(s)
var outputArray = [(Character,Character)]()
for i in 0..<strArray.count - 1 {
for j in i + 1..<strArray.count {
outputArray.append( (strArray[i], strArray[j]) )
}
}
return outputArray
}
So I want to create a suite of tests using XCTestCase. I usually use XCTestCase and XCTAssertEqual but these are only appropriate for C scalar types. This means that the following test case returns an error:
class pairsTests: XCTestCase {
func testNaive() {
measure {
XCTAssertEqual( pairsOfChars("abc") , [(Character("a"),Character("b")),(Character("a"),Character("c")),(Character("b"),Character("c")) ] )
}
}
}
I could convert to a string, but I'm thinking there is a better solution.
How can I test an output of an array of pairs of characters [(Character,Character)]
Your notion of a nonscalar is a total red herring. The problem is one of equatability.
How can I test an output of an array of pairs of characters [(Character,Character)]
You can't, because there is no default notion of what it would mean to equate two such arrays. This is the old "tuples of Equatable are not Equatable" problem (https://bugs.swift.org/browse/SR-1222) which still rears its head with arrays. The == operator works on tuples by a kind of magic, but they are still not formally Equatable.
You could define equatability of arrays of character pairs yourself:
typealias CharPair = (Character,Character)
func ==(lhs:[CharPair], rhs:[CharPair]) -> Bool {
if lhs.count != rhs.count {
return false
}
let zipped = zip(lhs,rhs)
return zipped.allSatisfy{$0 == $1}
}
Alternatively, have your pairsOfChars return something that is more easily made equatable, such as an array of a struct for which Equatable is defined.
For example:
struct CharacterPair : Equatable {
let c1:Character
let c2:Character
// in Swift 4.2 this next bit is not needed
static func ==(lhs:CharacterPair, rhs:CharacterPair) -> Bool {
return lhs.c1 == rhs.c1 && lhs.c2 == rhs.c2
}
}
func pairsOfChars(_ s: String) -> [CharacterPair] {
let strArray = Array(s)
var outputArray = [CharacterPair]()
for i in 0..<strArray.count - 1 {
for j in i + 1..<strArray.count {
outputArray.append(CharacterPair(c1:strArray[i],c2:strArray[j]))
}
}
return outputArray
}
You would then rewrite the test to match:
XCTAssertEqual(
pairsOfChars("abc"),
[CharacterPair(c1:Character("a"),c2:Character("b")),
CharacterPair(c1:Character("a"),c2:Character("c")),
CharacterPair(c1:Character("b"),c2:Character("c"))]
)

How can you check if an object is one of an array of types?

Given the following array:
let ignoredViewControllerTypes:[UIViewController.Type] = [
ViewControllerB.self,
ViewControllerC.self
]
let allViewControllers = [
viewControllerAInstance,
viewControllerBInstance,
viewControllerCInstance,
viewControllerDInstance
]
What is the syntax to filter allViewControllers so that it excludes those types in ignoredViewControllerTypes?
I have tried this, but it doesn't work:
let filteredControllers = allViewControllers.filter{ !ignoredViewControllerTypes.contains($0.self) }
So what am I missing?
This should work:
let filteredControllers = allViewControllers.filter { viewController in
!ignoredViewControllerTypes.contains(where: { type(of: viewController) == $0 })
}
Let's break it down in subtasks:
you want to check if a controller should be allowed or not
func isAllowed(_ controller: UIViewController) -> Bool {
return !ignoredViewControllerTypes.contains { controller.isKind(of: $0) }
}
you want to filter an array of controllers:
let filteredControllers = allViewControllers.filter(isAllowed)
Note that isAllowed also filters subclasses of the ignored controllers, if you want exact type match then you should use #dan's answer.
As a bonus, and because I like functional programming, you can make isAllowed a pure and flexible function by converting it to a high-order function:
func doesntBelong(to prohibitedClasses: [AnyClass]) -> (AnyObject) -> Bool {
return { obj in
prohibitedClasses.contains { obj.isKind(of: $0) }
}
}
, which can be used like this:
let filteredControllers = allViewControllers.filter(doesntBelong(to: ignoredViewControllerTypes))

How to write higher order functions like map, filter, reduce etc.?

I am trying to write or implement my own higher order function my way, but not able to write it.
In below code I tried to write filter.
var array : [String] = ["Sagar","Harshit","Parth","Gunja","Marmik","Sachin","Saurav"]
//Native filter function of Swift
array = array.filter { (name) -> Bool in
return name.prefix(1) == "S"
}
I implement below code, according to method signature of filter, but as I know , we can not write closure with return type(If possible then I don't know).
func filterArray(_ array : [String], completionHandler : (_ name : String) -> ()) -> (){
for (_, value) in array.enumerated(){
completionHandler(value)
}
}
self.filterArray(array) { (name) -> () in
if name.prefix(1) != "S"{
if let index = array.index(of: name){
array.remove(at: index)
}
}
}
My implementation working fine and filtering array. But I want to abstract logic of remove object from array.
Can we write our own higher order functions or not ?
If yes then please help to implement above one.
Thanks in advance.
And you can define a return type to a closure. You can find a working example below, but for this purpose I suggest using the Swift built in filter function which can provide the same solution and much faster.
var array : [String] = ["Sagar","Harshit","Parth","Gunja","Marmik","Sachin","Saurav"]
func filterArray(_ array : inout [String], condition: (_ name : String) -> Bool) -> (){
var filteredArray: [String] = []
for value in array {
if condition(value) {
filteredArray.append(value)
}
}
array = filteredArray
}
filterArray(&array) { (name) -> Bool in
return !name.hasPrefix("S")
}
print(array)
You can define your own higher order functions on collections.
There is a great session about collections where Soroush shows an example of writing your own higher order function extending a collection.
https://academy.realm.io/posts/try-swift-soroush-khanlou-sequence-collection/
// Swit built in filter
let numberOfAdmins = users.filter({ $0.isAdmin }).count // => fine
// Custom "filter"
let numberOfAdmins = users.count({ $0.isAdmin }) // => great
extension Sequence {
func count(_ shouldCount: (Iterator.Element) -> Bool) -> Int {
var count = 0
for element in self {
if shouldCount(element) {
count += 1
}
}
return count
}
}

swift generics return first and last element

I'm trying to get used to generics (never used them in objc) and want to write a toy function that takes an object of any type () and returns the first and last element. Hypothetically, I'd only use this on an array or a string - I keep getting an error that has no subscript members. I totally understand that the error message is telling me swift has no clue that T may potentially hold a type that does have subscripts - I just want to know how to get around this.
func firstAndLastFromCollection<T>(a:T?) {
var count: Int = 0
for item in a as! [AnyObject] {
count++
}
if count>1 {
var first = a?[0]
var last = a?[count-1]
return (first, last)
}
return something else here
}
Do I need to typecast somewhere here (which would kind of defeat the purpose here, as I'd need to downcast as either a string or an array, adding code and lessening how generic this func is)?
If you want to return the first and the last element then it's probably safe assuming the input param is an array of some kind of type.
So you can implement your function this way
func firstAndLast<T>(list:[T]) -> (first:T, last:T)? {
guard let first = list.first, last = list.last else { return nil }
return (first, last)
}
The function does return a tuple of 2 element, both have the same type of the generic element of the input array.
The returned tuple is an option because if the array is empty then nil is returned.
Examples
let nums = firstAndLast([1,2,3,4])
let words = firstAndLast(["One", "Two", "Three"])
As you can verify the type of the generic element into the array becomes the type of the elements inside the tuple.
In the example above nums is inferred to be (Int, Int)? and words (Words, Words)?
More examples
let emptyList: [String] = []
firstAndLast(emptyList) // nil
Extension
Finally you can also write this code as an extension of Array.
extension Array {
var firstAndLast: (first:Element, last:Element)? {
guard let first = self.first, last = self.last else { return nil }
return (first, last)
}
}
Now you can write
let aCoupleOfShows = ["Breaking Bad", "Better Call Saul", "Mr Robot"].firstAndLast
Again, if you check the type of the constant aCoupleOfShows you'll see that is a (first: String, last: String)?. Swift automatically did infer the correct type.
Last example
In the comments you said you wanted the first and last chars of a String. here it is the code if you use the extension above
if let chars = Array("Hello world".characters).firstAndLast {
print("First char is \(chars.first), last char is \(chars.last) ")
}
//>> First char is H, last char is d
If we are talking about collections, let's use the CollectionType:
func firstAndLastFromCollection<T: CollectionType>(a: T) -> (T.Generator.Element, T.Generator.Element)? {
guard !a.isEmpty else {
return nil
}
return (a.first!, a.lazy.reverse().first!)
}
print(firstAndLastFromCollection(["a", "b", "c"])) // ("a", "c")
print(firstAndLastFromCollection("abc".characters)) // ("a", "c")
print(firstAndLastFromCollection(0..<200)) // (0, 199)
print(firstAndLastFromCollection([] as [String])) // nil
If you specify your generic type to also conform to bidirectional index:
func firstAndLastFromCollection<T: CollectionType where T.Index : BidirectionalIndexType>(...) -> ...
then you can call last directly:
return (a.first!, a.last!)
If we decide to implement it using a category, we don't need generics at all:
extension CollectionType {
func firstAndLast() -> (Generator.Element, Generator.Element)? {
guard !self.isEmpty else {
return nil
}
return (self.first!, self.lazy.reverse().first!)
}
}
extension CollectionType where Index: BidirectionalIndexType {
func firstAndLast() -> (Generator.Element, Generator.Element)? {
guard !self.isEmpty else {
return nil
}
return (self.first!, self.last!)
}
}
print("abc".characters.firstAndLast())
Swift is a protocol oriented language. Usually you will find yourself extend protocols more than extending classes or structs.

How can I find the index of an item in Swift? [duplicate]

This question already has answers here:
How to find index of list item in Swift?
(23 answers)
Closed 7 years ago.
Is there a method called indexof or something similar?
var array = ["Jason", "Charles", "David"]
indexOf(array, "Jason") // Should return 0
EDIT: As of Swift 3.0, you should use the .index(where:) method instead and follow the change in the Swift 2.0 edit below.
EDIT: As of Swift 2.0, you should use the indexOf method instead. It too returns nil or the first index of its argument.
if let i = array.indexOf("Jason") {
print("Jason is at index \(i)")
} else {
print("Jason isn't in the array")
}
Use the find function. It returns either nil (if the value isn't found) or the first index of the value in the array.
if let i = find(array, "Jason") {
println("Jason is at index \(i)")
} else {
println("Jason isn't in the array")
}
In Swift 2.0 (Xcode 7.1b), you can use
if let result = array.indexOf("Jason")
while find(array, "Jason") is deprecated.
I made this function like above, but it return array of indexes
extension Array {
func indexesOf<T : Equatable>(object:T) -> [Int] {
var result: [Int] = []
for (index,obj) in enumerate(self) {
if obj as T == object {
result.append(index)
}
}
return result
}
}
Maybe it will be useful for you
Array can be bridged to an NSArray, so you can use:
array.bridgeToObjectiveC().indexOfObject("Jason")
An extension of Array can work wonders here. Here's an implementation shared in this StackOverflow answer:
extension Array {
func find (includedElement: T -> Bool) -> Int? {
for (idx, element) in enumerate(self) {
if includedElement(element) {
return idx
}
}
return nil
}
}
You can add an Array Extension that does exactly what you want, i.e:
extension Array {
func indexOf<T : Equatable>(x:T) -> Int? {
for i in 0..self.count {
if self[i] as T == x {
return i
}
}
return nil
}
}
Which now lets you use .indexOf() on all Swift arrays, e.g:
["Jason", "Charles", "David"].indexOf("Jason") //0
While the response from Max is great, it does not let you find multiple indexes of multiple objects, ie. indexes of the subset of the array. If you need that functionality, extensions are, as always, your best friend
func indexesOfSubset<T : Equatable>(objects : [T]) -> [Int] {
// Create storage for filtered objectsand results
var unusedObjects = objects
var result : [Int] = []
// Enumerate through all objects in array
for (index, obj) in enumerate(self) {
// Enumerate again through all objects that has not been found
for x in unusedObjects {
// If we hit match, append result, remove it from usused objects
if obj as! T == x {
result.append(index)
unusedObjects = unusedObjects.filter( { $0 != x } )
break
}
}
}
// Get results
return result
}
Note* : Works on Swift 1.2, if you want compatibility with 1.1, replace as! -> as