Chiel
Chiel

Reputation: 119

'T' is not identical to 'Int'

I'm trying some sample code in Swift and combined two principles: Array.map and Extension. Unfortunately, I get the error code "'T' is not identical to 'Int'" (line 3). So my question should probably be: how can I transform a T array into a Int array?

Thanks in advance for your answers!

Cheers.

extension Array {    
    func translateToDigitalNames()-> [String] {
        var numbers : [Int] = self

        let digitNames =
            [0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
            5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"]

        var strings = numbers.map {
            (var number) -> String in
            var output = ""
            while number > 0 {
                output = digitNames[number % 10]! + output
                number /= 10
            }
            return output
        }
        return strings
    }
}

let x = [26, 158, 610]
x.translateToDigitalNames()

Upvotes: 1

Views: 195

Answers (3)

Antonio
Antonio

Reputation: 72750

I would split the problem into 3 distinct subproblems.

The first is translating an integer into a string representation, implemented as a static method:

private static func translateToDigitalName(var number: Int) -> String {
    var output = ""

    while number > 0 {
        output = digitNames[number % 10]! + output
        number /= 10
    }

    return output
}

The reasons for making it a separate function are: separation of concerns, reusability, readability.

Next, we can implement a static method that, given an array of integers, returns an array of their respective string representations:

private static func translateToDigitalNames(numbers: [Int])-> [String] {
    return numbers.map { self.translateToDigitalName($0) }
}

Last, the actual array extension. The approach I'm using is to filter the array by excluding elements not castable to Int:

func translateToDigitalNames()-> [String] {
    let numbers: [Int] = self.filter { $0 is Int }.map { $0 as Int }
    return Array.translateToDigitalNames(numbers)
}

If you want the translation to fail if at least one array element is not an Int, just add an explicit check and return nil in that case:

func translateToDigitalNames()-> [String]? {
    let numbers: [Int] = self.filter { $0 is Int }.map { $0 as Int }

    if numbers.count != self.count {
        return nil
    }

    return Array.translateToDigitalNames(numbers)
}

Note that the return type is now an optional.

Last thing, rather than creating the digitNames array at every function invocation, I've moved it as a private global and immutable variable

The full code is available on this gist

Side note: the translateToDigitalNames and translateToDigitalName can be moved outside of the array extension, as global and public functions - and that's actually what I'd recommend in case you need to reuse them in the future.

Upvotes: 1

qwerty_so
qwerty_so

Reputation: 36295

It's not a good idea to write such kind of extension since it applies only to [Int] arrays. What should happen if you would do

["some", "strings"].translateToDigitalNames()

Instead use a function like this:

func translateToDigitalNames(numbers:[Int])-> [String] {

  let digitNames =
  [0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"]
  var strings = numbers.map {
    (var number) -> String in
    var output = ""
    while number > 0 {
      output = digitNames[number % 10]! + output
      number /= 10
    }
    return output
  }
  return strings
}

let x = [26, 158, 610]
translateToDigitalNames(x)

So the compiler ensures you always supply a [Int]

Upvotes: 1

Dániel Nagy
Dániel Nagy

Reputation: 12015

You can create the numbers array with a map function as well, like:

var numbers = map { $0 as Int }

Upvotes: 1

Related Questions