使用函数式编程将嵌套的字符串数组转换为嵌套的双精度数组

时间:2022-07-18 22:04:53

I'd like to convert nested array of strings into nested array of doubles

我想将嵌套的字符串数组转换为嵌套的双精度数组

example:

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

to

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

I tried

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

but in this case I obtain one array of double values, how to keep this array nested?

但在这种情况下,我获得了一个double值数组,如何保持这个数组嵌套?

EDIT:

Could you also elaborate why not using map() twice nor flatMap() twice? Why the right way to do this is to use map, then flatMap?

你能详细说明为什么不两次使用map(),也不使用flatMap()两次?为什么正确的方法是使用map,然后使用flatMap?

4 个解决方案

#1


2  

Let's try to sort things out. Array has a map() method

让我们尝试解决问题。 Array有一个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]

which creates a new array by transforming each element, and a flatMap() method

它通过转换每个元素和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]

which is similar but ignores the elements which are mapped to nil by the closure.

这是类似的但忽略了闭包映射到nil的元素。

And there is another flatMap() method

还有另一个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]

which transforms each element to a sequence and concatenates the results.

它将每个元素转换为序列并连接结果。

Your code calls the second flatMap() method to flatten the array to one dimension, and then the first flatMap() method to convert the strings to numbers.

您的代码调用第二个flatMap()方法将数组展平为一个维度,然后调用第一个将字符串转换为数字的flatMap()方法。


The first candidate for transforming arrays (or sequences in general) is map(), and that works for nested arrays as well:

转换数组(或一般的序列)的第一个候选者是map(),它也适用于嵌套数组:

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)]]

The result is a nested array of optionals because the conversion to a floating point value can fail. How to fix that?

结果是一个嵌套的可选项数组,因为转换为浮点值可能会失败。如何解决?

Forcefully unwrap (usually not recommended):

强力打开(通常不推荐):

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]]

That is fine if you have fixed data and can guarantee that each string is a valid floating point value. If not, the program will crash:

如果您有固定数据并且可以保证每个字符串都是有效的浮点值,那就没问题。如果没有,程序将崩溃:

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

Provide a default value:

提供默认值:

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]]

Here the invalid string is mapped to 0.0, so that the "shape" of the array is preserved. But 0.0 is a "magic number" now, and we cannot see from the result if it comes from a valid or an invalid string.

这里将无效字符串映射到0.0,以便保留数组的“形状”。但是0.0现在是一个“神奇的数字”,如果它来自有效或无效的字符串,我们无法从结果中看到。

Ignore invalid strings. And now flatMap() comes into play (the first version):

忽略无效字符串。现在flatMap()开始发挥作用(第一个版本):

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]]

The inner flatMap() returns an array of the non-nil Double($0) values, i.e. all invalid strings are ignored.

内部flatMap()返回非零双($ 0)值的数组,即忽略所有无效字符串。

Advantage: The code cannot crash due to invalid input, and no "magic numbers" are used. Possible disadvantage: The array shape is not preserved.

优点:代码不会因输入无效而崩溃,也不会使用“幻数”。可能的缺点:不保留数组形状。

So pick your choice!

所以选择你的选择!

#2


2  

In the first transformation you should use map instead of flatMap like the following:

在第一个转换中,您应该使用map而不是flatMap,如下所示:

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

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

#3


1  

Try like this.

试试这样吧。

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

One suggestion variable name always start with lower case so instead of Doubles and Strings write like doubles and strings .

一个建议变量名称始终以小写字母开头,因此而不是双打和字符串写入像双打和字符串。

#4


1  

Given this

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

You can write

你可以写

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

Shorter version

If you want a shorter version (slightly different from the other answers) then

如果你想要一个较短的版本(稍微不同于其他答案)那么

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

#1


2  

Let's try to sort things out. Array has a map() method

让我们尝试解决问题。 Array有一个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]

which creates a new array by transforming each element, and a flatMap() method

它通过转换每个元素和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]

which is similar but ignores the elements which are mapped to nil by the closure.

这是类似的但忽略了闭包映射到nil的元素。

And there is another flatMap() method

还有另一个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]

which transforms each element to a sequence and concatenates the results.

它将每个元素转换为序列并连接结果。

Your code calls the second flatMap() method to flatten the array to one dimension, and then the first flatMap() method to convert the strings to numbers.

您的代码调用第二个flatMap()方法将数组展平为一个维度,然后调用第一个将字符串转换为数字的flatMap()方法。


The first candidate for transforming arrays (or sequences in general) is map(), and that works for nested arrays as well:

转换数组(或一般的序列)的第一个候选者是map(),它也适用于嵌套数组:

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)]]

The result is a nested array of optionals because the conversion to a floating point value can fail. How to fix that?

结果是一个嵌套的可选项数组,因为转换为浮点值可能会失败。如何解决?

Forcefully unwrap (usually not recommended):

强力打开(通常不推荐):

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]]

That is fine if you have fixed data and can guarantee that each string is a valid floating point value. If not, the program will crash:

如果您有固定数据并且可以保证每个字符串都是有效的浮点值,那就没问题。如果没有,程序将崩溃:

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

Provide a default value:

提供默认值:

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]]

Here the invalid string is mapped to 0.0, so that the "shape" of the array is preserved. But 0.0 is a "magic number" now, and we cannot see from the result if it comes from a valid or an invalid string.

这里将无效字符串映射到0.0,以便保留数组的“形状”。但是0.0现在是一个“神奇的数字”,如果它来自有效或无效的字符串,我们无法从结果中看到。

Ignore invalid strings. And now flatMap() comes into play (the first version):

忽略无效字符串。现在flatMap()开始发挥作用(第一个版本):

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]]

The inner flatMap() returns an array of the non-nil Double($0) values, i.e. all invalid strings are ignored.

内部flatMap()返回非零双($ 0)值的数组,即忽略所有无效字符串。

Advantage: The code cannot crash due to invalid input, and no "magic numbers" are used. Possible disadvantage: The array shape is not preserved.

优点:代码不会因输入无效而崩溃,也不会使用“幻数”。可能的缺点:不保留数组形状。

So pick your choice!

所以选择你的选择!

#2


2  

In the first transformation you should use map instead of flatMap like the following:

在第一个转换中,您应该使用map而不是flatMap,如下所示:

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

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

#3


1  

Try like this.

试试这样吧。

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

One suggestion variable name always start with lower case so instead of Doubles and Strings write like doubles and strings .

一个建议变量名称始终以小写字母开头,因此而不是双打和字符串写入像双打和字符串。

#4


1  

Given this

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

You can write

你可以写

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

Shorter version

If you want a shorter version (slightly different from the other answers) then

如果你想要一个较短的版本(稍微不同于其他答案)那么

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