Convert String type array to Float type array in swift Cannot assign value of type 'String' to subscript of type 'Double'

Viewed 374

How can I convert the "numbersString" array that has String type values to a "numbersFloat" array with float type values

The problem is that I keep getting "Cannot assign value of type 'String' to subscript of type 'Double'" as an error

I understand that I am not able to input a Float value to a String subscript, but I can't neither change the Strings because they are comma separated and can't put the values in the array

var numbersString = [["564,00", "577,00", "13,00"], ["563,00", "577,00", "14,00"]] → I have
var numbersFloat = [[564.00, 577.00, 13.00], [563.00, 577.00, 14.00]] → I need

Things I have tried:

for row in 0...numbersString.count-1 {
    for col in 0...numbersString[0].count-1 {
        numbersFloat[row][col] = numbersString[row][col]
    }
}
Error: Cannot assign value of type 'String' to subscript of type 'Double'
for row in 0...numbersString.count-1 {
    for col in 0...numbersString[0].count-1 {
            var a = table[row][col]
            table[row][col] = Float(a)
    }
}
3 Answers

You can use a NumberFormatter to handle strings containing floats that use commas as their decimal separators. I generally wrap custom formatters in a class. That would look something like this:

class FloatFormatter {
    let formatter: NumberFormatter
    init() {
        formatter = NumberFormatter()
        formatter.decimalSeparator = ","
    }

    func float(from string: String) -> Float? {
        formatter.number(from: string)?.floatValue
    }
}

Substituting this into your example code (with a fix to the type of your float array) you get:

var numbersString = [["564,00", "577,00", "13,00"], ["563,00", "577,00", "14,00"]]
var numbersFloat: [[Float]] = [[564.00, 577.00, 13.00], [563.00, 577.00, 14.00]]

let floatFormatter = FloatFormatter()
for row in 0...numbersString.count-1 {
    for col in 0...numbersString[0].count-1 {
        numbersFloat[row][col] = floatFormatter.float(from: numbersString[row][col])!
    }
}

This works, but it's not very Swifty. Using map would be better (that way you do not need to worry about matching the sizes of your arrays and pre-allocating the float array).

let floatFormatter = FloatFormatter()
let numbersString = [["564,00", "577,00", "13,00"], ["563,00", "577,00", "14,00"]]
let numbersFloat = numbersString.map { (row: [String]) -> [Float] in
    return row.map { stringValue  in
        guard let floatValue = floatFormatter.float(from: stringValue) else {
            fatalError("Failed to convert \(stringValue) to float.")
        }
        return floatValue
    }
}

Maybe you want something like this?

var numbersString = [["564.00", "577.00", "13.00"], ["563.00", "577.00", "14.00"]]

var numbersFloat: [[Float]] = Array(repeating: Array(repeating: 0.0, count: numbersString[0].count), count: numbersString.count)

print(numbersFloat.count)
for row in 0...numbersString.count - 1 {
    for col in 0...numbersString[0].count - 1 {

        print(row, col, numbersString[row][col])
        print(Float(numbersString[row][col]) ?? 0)
        numbersFloat[row][col] =  Float(numbersString[row][col]) ?? 0
    }
}

This will work with both "." and "," separator.

var numbersString = [["564,00", "577,00", "13,00"], ["563,00", "577,00", "14,00"]]

let numberFormatter = NumberFormatter()
let decimalSeparator = ","
numberFormatter.decimalSeparator = decimalSeparator

let numbersFloat = numbersString.map({ $0.compactMap({ numberFormatter.number(from: $0.replacingOccurrences(of: ".", with: decimalSeparator))?.floatValue })})

For everyone: NumberFormatter has .locale property and when formatter is created, locale is set to current device locale. But decimal separators differs in different countries. It can lead to very unpleasant bugs when everything works good for you and even for QAs, but doesn't work for users in production. So it is always best option to control String-to-Double conversion in described way.

Related