IamMashed IamMashed - 6 months ago 16
Swift Question

Convert string array representation of integers into array of integers in Swift

How can I convert this:

let numbersStringArray = "[-1, -2, -3, -4, -5, 6, -7, -8, -9, -10]"


into an array of integers:

[-1, -2, -3, -4, -5, 6, -7, -8, -9, -10]


I know one way to implement thin swift is to do like this:

let formatter = NSNumberFormatter()
var numbers = numbersStringArray.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: "[]")).componentsSeparatedByString(",").map { formatter.numberFromString($0)?.integerValue
}


But I need more shorter coded solution please.

Answer

I would like something shorter if possible. Something like Array(numbersStringArray)

You can do this by simply creating a convenience initialiser through an Array extension.

For example, decoding the string through JSON, as @Eric D suggests:

extension Array {
    init?(fromJSONString str:String) {
        guard let data = numbersStringArray.dataUsingEncoding(NSUTF8StringEncoding),
            json = try? NSJSONSerialization.JSONObjectWithData(data, options: []),
            array = json as? [Element] else {return nil}

        self.init(array)
    }
}

let numbersStringArray = "[-1, -2, -3, -4, -5, 6, -7, -8, -9, -10]"

if let numberArray:[Int] = Array(fromJSONString: numbersStringArray) {
    print(numberArray) // prints: [-1, -2, -3, -4, -5, 6, -7, -8, -9, -10]
}

Here we're returning an optional array to reflect the fact that the types could mismatch (the conditional downcasting to [Element] could fail), or the JSON serialisation or data encoding itself could fail.

Or spitting the string up manually as @vadian suggests:

protocol StringInitialisable {
    init?(string: String)
}

extension Int : StringInitialisable {
    init?(string: String) {self.init(string)}
}

extension Array where Element : StringInitialisable  {

    init(fromString str:String) {
        let arr = str.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: "[]"))
            .componentsSeparatedByString(", ")
            .flatMap {Element(string:$0)}
        self.init(arr)
    }
}

let numbersStringArray = "[-1, -2, -3, -4, -5, 6, -7, -8, -9, -10]"

let numberArray:[Int] = Array(fromString: numbersStringArray)
print(numberArray) // prints: [-1, -2, -3, -4, -5, 6, -7, -8, -9, -10]

We're using a protocol here in order to explicitly specify the types that can be used for this initialiser – namely those that can be initialised with a string. This method won't return an optional if the type casting fails, it will simply exclude any type mismatches from the returned array. You could change it fairly easily to return an optional result if you want though.

Note that we have to explicitly denote the type of the array in both cases due to the fact that Swift cannot infer the return type of the arrays, as you're just passing it a string.

Which method you use is completely up to you – if your string is always in a JSON format, then I would recommend going with the first option for increased flexibility.

Comments