arrays - vacio - swift string array example




¿Cómo puedo extender matrices mecanografiadas en Swift? (6)

( Swift 2.x )

También puede ampliar la matriz para cumplir con un protocolo que contenga blue-rpints para métodos de tipo genérico, por ejemplo, un protocolo que contenga sus utilidades funcionales personalizadas para todos los elementos de matriz genéricos que se ajusten a alguna restricción de tipo, por ejemplo, el protocolo MyTypes . La ventaja de usar este enfoque es que puede escribir funciones tomando argumentos de matriz genéricos, con la restricción de que estos argumentos de matriz deben ajustarse a su protocolo de utilidades de función personalizado, por ejemplo, el protocolo MyFunctionalUtils .

Puede obtener este comportamiento de forma implícita, mediante el tipo que restringe los elementos de la matriz a MyTypes , o --- como mostraré en el método que describo a continuación ---, bastante clara y explícitamente, dejando que el encabezado genérico de funciones de matriz muestre directamente esa entrada arrays se ajusta a MyFunctionalUtils .

Comenzamos con los Protocolos MyTypes para usarlos como restricción de tipo; extienda los tipos que desea encajar en sus genéricos mediante este protocolo (el ejemplo siguiente amplía los tipos fundamentales Int y Double así como un tipo personalizado MyCustomType )

/* Used as type constraint for Generator.Element */
protocol MyTypes {
    var intValue: Int { get }
    init(_ value: Int)
    func *(lhs: Self, rhs: Self) -> Self
    func +=(inout lhs: Self, rhs: Self)
}

extension Int : MyTypes { var intValue: Int { return self } }
extension Double : MyTypes { var intValue: Int { return Int(self) } }
    // ...

/* Custom type conforming to MyTypes type constraint */
struct MyCustomType : MyTypes {
    var myInt : Int? = 0
    var intValue: Int {
        return myInt ?? 0
    }

    init(_ value: Int) {
        myInt = value
    }
}

func *(lhs: MyCustomType, rhs: MyCustomType) -> MyCustomType {
    return MyCustomType(lhs.intValue * rhs.intValue)
}

func +=(inout lhs: MyCustomType, rhs: MyCustomType) {
    lhs.myInt = (lhs.myInt ?? 0) + (rhs.myInt ?? 0)
}

Protocolo MyFunctionalUtils (que contiene planos de nuestras funciones genéricas adicionales de funciones de matriz) y, posteriormente, la extensión de Array by MyFunctionalUtils ; implementación de método (s) impresos en azul:

/* Protocol holding our function utilities, to be used as extension 
   o Array: blueprints for utility methods where Generator.Element 
   is constrained to MyTypes */
protocol MyFunctionalUtils {
    func foo<T: MyTypes>(a: [T]) -> Int?
        // ...
}

/* Extend array by protocol MyFunctionalUtils and implement blue-prints 
   therein for conformance */
extension Array : MyFunctionalUtils {
    func foo<T: MyTypes>(a: [T]) -> Int? {
        /* [T] is Self? proceed, otherwise return nil */
        if let b = self.first {
            if b is T && self.count == a.count {
                var myMultSum: T = T(0)

                for (i, sElem) in self.enumerate() {
                    myMultSum += (sElem as! T) * a[i]
                }
                return myMultSum.intValue
            }
        }
        return nil
    }
}

Finalmente, las pruebas y dos ejemplos que muestran una función tomando matrices genéricas, con los siguientes casos, respectivamente

  1. Se muestra la afirmación implícita de que los parámetros de la matriz se ajustan al protocolo 'MyFunctionalUtils', a través del tipo que restringe los elementos de arrays a 'MyTypes' (función bar1 ).

  2. Mostrar explícitamente que los parámetros de la matriz se ajustan al protocolo 'MyFunctionalUtils' (función bar2 ).

La prueba y ejemplos a continuación:

/* Tests & examples */
let arr1d : [Double] = [1.0, 2.0, 3.0]
let arr2d : [Double] = [-3.0, -2.0, 1.0]

let arr1my : [MyCustomType] = [MyCustomType(1), MyCustomType(2), MyCustomType(3)]
let arr2my : [MyCustomType] = [MyCustomType(-3), MyCustomType(-2), MyCustomType(1)]

    /* constrain array elements to MyTypes, hence _implicitly_ constraining
       array parameters to protocol MyFunctionalUtils. However, this
       conformance is not apparent just by looking at the function signature... */
func bar1<U: MyTypes> (arr1: [U], _ arr2: [U]) -> Int? {
    return arr1.foo(arr2)
}
let myInt1d = bar1(arr1d, arr2d) // -4, OK
let myInt1my = bar1(arr1my, arr2my) // -4, OK

    /* constrain the array itself to protocol MyFunctionalUtils; here, we
       see directly in the function signature that conformance to
       MyFunctionalUtils is given for valid array parameters */
func bar2<T: MyTypes, U: protocol<MyFunctionalUtils, _ArrayType> where U.Generator.Element == T> (arr1: U, _ arr2: U) -> Int? {

    // OK, type U behaves as array type with elements T (=MyTypes)
    var a = arr1
    var b = arr2
    a.append(T(2)) // add 2*7 to multsum
    b.append(T(7))

    return a.foo(Array(b))
        /* Ok! */
}
let myInt2d = bar2(arr1d, arr2d) // 10, OK
let myInt2my = bar2(arr1my, arr2my) // 10, OK

¿Cómo puedo extender el tipo Array<T> o T[] Swift con utilidades funcionales personalizadas?

Al examinar los documentos API de Swift, se muestra que los métodos de Array son una extensión de T[] , por ejemplo:

extension T[] : ArrayType {
    //...
    init()

    var count: Int { get }

    var capacity: Int { get }

    var isEmpty: Bool { get }

    func copy() -> T[]
}

Al copiar y pegar la misma fuente e intentar cualquier variación como:

extension T[] : ArrayType {
    func foo(){}
}

extension T[] {
    func foo(){}
}

No se puede construir con el error:

El tipo nominal T[] no puede extenderse

El uso de la definición de tipo completo falla con el Use of undefined type 'T' , es decir:

extension Array<T> {
    func foo(){}
}

Y también falla con Array<T : Any> y Array<String> .

Curiosamente Swift me permite extender una matriz sin tipo con:

extension Array {
    func each(fn: (Any) -> ()) {
        for i in self {
            fn(i)
        }
    }
}

Lo cual me permite llamar con:

[1,2,3].each(println)

Pero no puedo crear una extensión de tipo genérica adecuada ya que el tipo parece estar perdido cuando fluye a través del método, por ejemplo, tratando de reemplazar el filtro incorporado de Swift con :

extension Array {
    func find<T>(fn: (T) -> Bool) -> T[] {
        var to = T[]()
        for x in self {
            let t = x as T
            if fn(t) {
                to += t
            }
        }
        return to
    }
}

Pero el compilador lo trata como sin tipo donde todavía permite llamar a la extensión con:

["A","B","C"].find { $0 > "A" }

Y cuando se Swift.String con un depurador indica que el tipo es Swift.String pero es un error de compilación intentar acceder a él como una cadena sin convertirlo primero en String , es decir:

["A","B","C"].find { ($0 as String).compare("A") > 0 }

¿Alguien sabe cuál es la forma correcta de crear un método de extensión tipeado que actúe como las extensiones integradas?


Después de un tiempo intentando cosas diferentes, la solución parece eliminar la <T> de la firma como:

extension Array {
    func find(fn: (T) -> Bool) -> [T] {
        var to = [T]()
        for x in self {
            let t = x as T;
            if fn(t) {
                to += t
            }
        }
        return to
    }
}

Que ahora funciona como se pretendía sin errores de compilación:

["A","B","C"].find { $0.compare("A") > 0 }

Para extender matrices tipadas con clases , lo siguiente funciona para mí (Swift 2.2 ). Por ejemplo, clasificando una matriz tipada:

class HighScoreEntry {
    let score:Int
}

extension Array where Element:HighScoreEntry {
    func sort() -> [HighScoreEntry] {
      return sort { $0.score < $1.score }
    }
}

Intentar hacer esto con una struct o typealias dará un error:

Type 'Element' constrained to a non-protocol type 'HighScoreEntry'

Actualización :

Para extender matrices tipadas con no clases, use el siguiente enfoque:

typealias HighScoreEntry = (Int)

extension SequenceType where Generator.Element == HighScoreEntry {
    func sort() -> [HighScoreEntry] {
      return sort { $0 < $1 }
    }
}

En Swift 3 algunos tipos han sido renombrados:

extension Sequence where Iterator.Element == HighScoreEntry 
{
    // ...
}

Si desea obtener más información sobre la extensión de matrices y otros tipos de compilación en el código de pago de clases en este repositorio github https://github.com/ankurp/Cent

A partir de Xcode 6.1, la sintaxis para extender matrices es la siguiente

extension Array {
    func at(indexes: Int...) -> [Element] {
        ... // You code goes herer
    }
}

Usando Swift 2.2 : me encontré con un problema similar cuando trataba de eliminar duplicados de una matriz de cadenas. Pude agregar una extensión en la clase Array que hace exactamente lo que estaba buscando hacer.

extension Array where Element: Hashable {
    /**
     * Remove duplicate elements from an array
     *
     * - returns: A new array without duplicates
     */
    func removeDuplicates() -> [Element] {
        var result: [Element] = []
        for value in self {
            if !result.contains(value) {
                result.append(value)
            }
        }
        return result
    }

    /**
     * Remove duplicate elements from an array
     */
    mutating func removeDuplicatesInPlace() {
        var result: [Element] = []
        for value in self {
            if !result.contains(value) {
                result.append(value)
            }
        }
        self = result
    }
}

Agregar estos dos métodos a la clase Array me permite llamar a uno de los dos métodos en una matriz y eliminar correctamente los duplicados. Tenga en cuenta que los elementos en la matriz deben ajustarse al protocolo Hashable. Ahora puedo hacer esto:

 var dupes = ["one", "two", "two", "three"]
 let deDuped = dupes.removeDuplicates()
 dupes.removeDuplicatesInPlace()
 // result: ["one", "two", "three"]

import Foundation

extension Array {

    func calculateMean() -> Double {
        // is this an array of Doubles?
        if self.first is Double {
            // cast from "generic" array to typed array of Doubles
            let doubleArray = self.map { $0 as! Double }

            // use Swift "reduce" function to add all values together
            let total = doubleArray.reduce(0.0, combine: {$0 + $1})

            let meanAvg = total / Double(self.count)
            return meanAvg

        } else {
            return Double.NaN
        }
    }

    func calculateMedian() -> Double {
        // is this an array of Doubles?
        if self.first is Double {
            // cast from "generic" array to typed array of Doubles
            var doubleArray = self.map { $0 as! Double }

            // sort the array
            doubleArray.sort( {$0 < $1} )

            var medianAvg : Double
            if doubleArray.count % 2 == 0 {
                // if even number of elements - then mean average the middle two elements
                var halfway = doubleArray.count / 2
                medianAvg = (doubleArray[halfway] + doubleArray[halfway - 1]) / 2

            } else {
                // odd number of elements - then just use the middle element
                medianAvg = doubleArray[doubleArray.count  / 2 ]
            }
            return medianAvg
        } else {
            return Double.NaN
        }

    }

}




swift