Convierta una matriz anidada de cadenas en una matriz anidada de dobles utilizando la functional programming.

Me gustaría convertir una matriz anidada de cadenas en una matriz anidada de dobles.

ejemplo:

let Strings = [["1.1", "1.2"],["2.1", "2.2"]] 

a

 let Doubles = [[1.1, 1.2],[2.1, 2.2]] 

Lo intenté

 let Doubles = Strings.flatMap(){$0}.flatMap(){Double($0)} 

pero en este caso obtengo una matriz de valores dobles, ¿cómo mantener anidada esta matriz?

EDITAR:

¿Podrías también explicar por qué no usar map() dos veces ni flatMap() dos veces? ¿Por qué la forma correcta de hacer esto es usar el map y luego el map flatMap ?

Intentemos orderar las cosas. Array tiene un método map()

 /// Returns an array containing the results of mapping the given closure /// over the sequence's elements. public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T] 

que crea una nueva matriz mediante la transformación de cada elemento, y un método flatMap()

 /// Returns an array containing the non-`nil` results of calling the given /// transformation with each element of this sequence. public func flatMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] 

que es similar pero ignora los elementos que son asignados a nil por el cierre.

Y hay otro método flatMap()

 /// Returns an array containing the concatenated results of calling the /// given transformation with each element of this sequence. public func flatMap<SegmentOfResult : Sequence>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Iterator.Element] 

que transforma cada elemento en una secuencia y concatena los resultados.

Su código llama al segundo método flatMap() para acoplar la matriz a una dimensión, y luego al primer método flatMap() para convertir las cadenas a numbers.


El primer candidato para transformar matrices (o secuencias en general) es map() , y eso también funciona para matrices anidadas:

 let strings = [["1.0", "2.0"],["3.0", "4.0"]] let doubles = strings.map { $0.map { Double($0) }} print(doubles) // [[Optional(1.0), Optional(2.0)], [Optional(3.0), Optional(4.0)]] 

El resultado es una matriz anidada de opciones porque la conversión a un valor de punto flotante puede fallar. ¿Cómo arreglar eso?

Desenrolle con fuerza (generalmente no se recomienda):

 let strings = [["1.0", "2.0"],["3.0", "4.0"]] let doubles = strings.map { $0.map { Double($0)! }} print(doubles) // [[1.0, 2.0], [3.0, 4.0]] 

Eso está bien si ha fijado datos y puede garantizar que cada cadena sea un valor de punto flotante válido. De lo contrario, el progtwig se bloqueará:

 let strings = [["1.0", "2.0"],["3.0", "wot?"]] let doubles = strings.map { $0.map { Double($0)! }} // fatal error: unexpectedly found nil while unwrapping an Optional value 

Proporcione un valor pnetworkingeterminado:

 let strings = [["1.0", "2.0"],["3.0", "wot?"]] let doubles = strings.map { $0.map { Double($0) ?? 0.0 }} print(doubles) // [[1.0, 2.0], [3.0, 0.0]] 

Aquí, la cadena no válida se asigna a 0.0 , de modo que se conserva la "forma" de la matriz. Pero 0.0 es un "número mágico" ahora, y no podemos verlo a partir del resultado si proviene de una cadena válida o inválida.

Omita cadenas no válidas. Y ahora flatMap() entra en juego (la primera versión):

 let strings = [["1.0", "2.0"],["3.0", "wot?"]] let doubles = strings.map { $0.flatMap { Double($0) }} print(doubles) // [[1.0, 2.0], [3.0]] 

El flatMap() interno devuelve una matriz de los valores Double($0) no nulos, es decir, se ignoran todas las cadenas inválidas.

Ventaja: el código no se puede bloquear debido a una input no válida, y no se utilizan "numbers mágicos". Posible desventaja: la forma de la matriz no se conserva.

¡Así que elige tu elección!

En la primera transformación, debe usar el map en lugar de flatMap como el siguiente:

let doubles = Strings.map { $0.flatMap {Double($0)} }

Intente así.

 let doubles = strings.map { $0.flatMap { Double($0) } } 

Un nombre de variable de sugerencia siempre comienza con minúsculas, por lo que en lugar de Doubles y Strings escribe como doubles y strings .

Dado este

 let strings = [["1.1", "1.2"], ["2.1", "2.2"]] 

Puedes escribir

 let doubles: [[Double]] = strings.map { elms -> [Double] in return elms.flatMap { Double($0) } } 

Versión más corta

Si desea una versión más corta (ligeramente diferente de las otras respuestas), entonces

 let doubles = strings.map { $0.flatMap(Double.init) }