Generics in Swift

I am learning Generics in Swift. This topic is quite difficult for me to understand. There are two problems with generics in the book I'm reading:

1st challenge : he asks to write a function findAll(_:_:)

that accepts an array of any type T, which conforms to the Equatable protocol and one element (also of type T). findAll(_:_:)

should return an array of integers corresponding to each location where the element was found in the array. For example, it findAll([5,3,7,3,9], 3]

should return [1,3]

.

The second task is change findAll(_:_:)

to accept a collection instead of an array, and it gives a hint: "You will need to change the return type from [Int] to an array of associated collection protocol type"

This is what I did for the first call

func findAll<T:Equatable> (_ first: [T], _ second: T) -> [Int] {
var array = [Int]()

for i in 0..<first.count {
    if first[i] == second {
        array.append(i)
        }
    }   
return array
}

      

For the second task, what I'm thinking about is a generic function that I can pass to a Collection (could be Array, Dictionary or Set). But for the Set type , since it is in no particular order, how do you find the location of the item in Set ?

Thank.

+3


source to share


2 answers


The subscript collection method is defined as

public subscript(position: Self.Index) -> Self.Iterator.Element { get }

      

which means that your function must take as arguments

  • collection C

    and
  • associated type value C.Iterator.Element

and return an array C.Index

. In addition, the element type must be Equatable

:

func findAll<C: Collection> (_ collection: C, _ element: C.Iterator.Element) -> [C.Index]
    where C.Iterator.Element: Equatable
{ ... }

      

As with your solution for arrays, collection indices can be:

func findAll<C: Collection> (_ collection: C, _ element: C.Iterator.Element) -> [C.Index]
where C.Iterator.Element: Equatable
{
    var result: [C.Index] = []

    var idx = collection.startIndex
    while idx != collection.endIndex {
        if collection[idx] == element {
            result.append(idx)
        }
        collection.formIndex(after: &idx)
    }

    return result
}

      

One would expect something like

for idx in collection.startIndex ..< collection.endIndex
// or
for idx in collection.indices

      

works, but (in Swift 3) it requires an additional constraint on the bound type Indices

:



func findAll<C: Collection> (_ collection: C, _ element: C.Iterator.Element) -> [C.Index]
    where C.Iterator.Element: Equatable, C.Indices.Iterator.Element == C.Index
{

    var result: [C.Index] = []

    for idx in collection.indices {
        if collection[idx] == element {
            result.append(idx)
        }
    }

    return result
}

      

This is no longer required in Swift 4, see, for example, Cannot use indices.contains () in Collection Extension in Swift 3 for a good explanation.

This can now be simplified using filter

:

func findAll<C: Collection> (_ collection: C, _ element: C.Iterator.Element) -> [C.Index]
    where C.Iterator.Element: Equatable, C.Indices.Iterator.Element == C.Index
{
    return collection.indices.filter { collection[$0] == element }
}

      

Example (collection Character

):

let chars = "abcdabcdabcd".characters
let indices = findAll(chars, "c")
for idx in indices {
    print(chars[idx])
}

      

Set

also is Collection

, it has an associated Index

type and method subscript

. Example:

let set = Set([1, 2, 3, 4, 5, 6, 7, 8, 9])
let indices = findAll(set, 3)
for idx in indices {
    print(set[idx])
}

      

Finally, you can define a function as a method by type Collection

:

extension Collection where Iterator.Element: Equatable, Indices.Iterator.Element == Index {
    func allIndices(of element: Iterator.Element) -> [Index] {
        return indices.filter { self[$0] == element }
    }
}

// Example:
let indices = [1, 2, 3, 1, 2, 3].allIndices(of: 3)

      

+2


source


To create your own function definition, you must create an extension for the type to which the function belongs. From there the tag should be used override

so that you can create your own implementation for this function. More specifically, to create a function that takes a collection instead of an array, create an overridden version of the function that takes a collection instead.

Also please show us what you have tried so far instead of just saying that I have tried a few things.

Here are some links that might be helpful:



Swift Documentation

Override function

Another simple example of overriding is that whenever the ViewContoller class is created, the viewDidLoad () method, which sets the view, is often overridden.

0


source







All Articles