arrays join swift sequence

arrays - En Swift, me gustaría "unirme" a dos secuencias en una secuencia de tuplas



join sequence (5)

Me gustaría unir dos (o más) secuencias que luego crearían una secuencia de tuplas. Donde la primera tupla contendría el primer elemento de cada secuencia y la segunda tupla contendría los segundos elementos, etc. A continuación se muestra una función de ejemplo que toma dos matrices y crea una tercera matriz de tuplas. Entonces puedo usar esta secuencia para procesar con las funciones map (), filter () y reduce ().

Mi ejemplo funciona, pero falta de muchas maneras. Es para matrices, no para todas las secuencias. Deja de generar tuplas cuando la primera secuencia se queda sin elementos. Me gustaría que nils esté en las tuplas para las secuencias cortas que ya no pueden proporcionar elementos. Es solo para dos arreglos, me gustaría que fuera para cualquier cantidad de secuencias,

Las soluciones parciales serían útiles. Soy un novato de programación funcional por lo que también se apreciará el nombre apropiado para esta función. Tal vez ya está en la biblioteca de switfz, simplemente sé cómo se llama. Elegí "unirse" porque es más o menos similar a la "combinación" de SQL que también construye tuplas (también conocidas como filas)

func join<T> (s1: Array<T>, s2: Array<T>) -> Array<(T,T)> { var g1 = s1.generate(); var g2 = s2.generate(); var result:Array<(T,T)> = [] while let e1 = g1.next() { if let e2 = g2.next() { result.append((e1,e2)) } } return result } class Hamming { class func compute(input: String, against: String) -> Int { return join(Array(input),Array(against)).reduce(0){ return ($1.0 != $1.1) ? $0 + 1 : $0 } } } Hamming.compute("abcde","abcdf") // 1


¿Por qué no usar Zip2 ?

reduce(Zip2("abcde","abcdf"), 0) { (d, c) in return d + (c.0 != c.1 ? 1 : 0) } // 1


Ya hay una función para eso llamada Zip2 :

var first = [0,1,2,3] var second = ["zero", "one", "two", "three"] Array(Zip2(first,second)) // (0, "zero"), (1, "one"), (2, "two"), (3, "three")

Sin embargo, esta función no se rellena con nil y también utiliza la más corta de las dos secuencias pasadas. Sin embargo, tenga en cuenta que no requiere que los tipos coincidan entre las dos secuencias y que toma cualquier secuencia, no solo las matrices.

Aquí está mi propia implementación personalizada de Zip2WithNilPadding:

struct Zip2WithNilPadding<T: SequenceType,U: SequenceType>: SequenceType { typealias Generator = GeneratorOf<(T.Generator.Element?, U.Generator.Element?)> let first: T let second: U init(_ first: T, _ second: U) { self.first = first self.second = second } func generate() -> Generator { var generator1: T.Generator? = first.generate() var generator2: U.Generator? = second.generate() return GeneratorOf<(T.Generator.Element?, U.Generator.Element?)>() { let element1 = generator1?.next() let element2 = generator2?.next() if element1 == nil && element2 == nil { return nil } else if element1 == nil{ generator1 = nil } else if element2 == nil { generator2 = nil } return (element1, element2) } } } var first = [0,1,2] var second = ["zero", "one", "two", "three", "four"] Array(Zip2WithNilPadding(first, second))

Si tiene preguntas sobre la implementación específica, infórmeme e intentaré aclararlas. Esta implementación también debería ayudarlo a crear un Zip que tome una matriz de secuencias. Lamentablemente, en ese caso, todos tendrían que ser una secuencia del mismo tipo porque no puede tener una cantidad variable de genéricos.


La sintaxis ha sido cambiada a Zip2Sequence :

Array(Zip2Sequence(arr, second))


A partir de Swift 3, ahora hay una función gratuita para crear una secuencia Zip2Sequence:

let s = ["a", "b", "c"] let n = [1, 2, 3] let zipped = zip(s, n) // Zip2Sequence<[String], [Int]> let zippedArray = Array(zipped) // [(String, Int)]


Aquí hay una versión Swift 4 de la respuesta de drewag. Lo empaqué como un paquete Swift 4 en GitHub, junto con algunas pruebas: https://github.com/danramteke/Zip2WithNilPadding

Aquí está el código relevante en Swift 4:

public struct Zip2WithNilPadding<T: Sequence, U: Sequence>: Sequence { public typealias Iterator = AnyIterator<(T.Iterator.Element?, U.Iterator.Element?)> public let first: T public let second: U public init(_ first: T, _ second: U) { self.first = first self.second = second } public func makeIterator() -> Iterator { var iterator1: T.Iterator? = first.makeIterator() var iterator2: U.Iterator? = second.makeIterator() return Iterator() { let element1 = iterator1?.next() let element2 = iterator2?.next() if element1 == nil && element2 == nil { return nil } else { return (element1, element2) } } } }