Search code examples
iosarraysswiftcomparison

Create a comparison in an array


I working on an app to show some information about cities

In an array I have two parameters 1- languages (I don't know how many there are) 2- the number of people that speak on that language

I get this data from an server

here is this two paramter in JSon

"language": "French",
"number": "12321",

these data among other data is saved in an array

I Just want to get the most used language with the pecentage for example French with 35% how can I do it in swift?

Your help will be appreciated.


Solution

  • import Foundation
    
    let serverOutput = Data("""
    [
        {
            "language": "French",
            "number": "12"
        },
        {
            "language": "English",
            "number": "10"
        }
    ]
    """.utf8)
    
    struct LangueUsers: Codable {
        let language: String
        let number: Int
    
        enum CodingKeys: CodingKey {
            case language
            case number
        }
    
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            language = try container.decode(String.self, forKey: .language)
            let rawNumber = try container.decode(String.self, forKey: .number)
            guard let number = Int(rawNumber) else {
                throw DecodingError.typeMismatch(Int.self, DecodingError.Context(codingPath: [CodingKeys.number], debugDescription: "\(rawNumber) can't be convert to Int"))
            }
            self.number = number
        }
    }
    
    struct LangueUsersPercent: CustomStringConvertible {
        let language: String
        let share: Double
    
        init(language: String, number: Int, all: Int) {
            self.language = language
            self.share = Double(number) / Double(all)
        }
    
        var description: String {
            return String(format: "%@ - %0.1f%%", language, share * 100)
        }
    }
    
    let decoder = JSONDecoder()
    //1
    var output = try decoder.decode([LangueUsers].self, from: serverOutput)
    //2
    let allUser = output.reduce(0) { (reult, languageUsers) -> Int in
        reult + Int(languageUsers.number)
    }
    //3
    output.sort { (lhs, rhs) -> Bool in
        lhs.number > rhs.number
    }
    //4
    let response = output.map {
        LangueUsersPercent(language: $0.language, number: $0.number, all: allUser)
    }
    print(response[0])
    

    The code assumes that the output from a server is in serverOutput variable. So steps need to achieve your task:

    1. decode your JSON to swift structure (called LangueUsers) using swift codable. Keep in mind that by default it won't convert string values to int, so I have to create a custom init(from decoder: Decoder) initializer
    2. count the sum of all users (you can do it using for loop or reduce like in my example)
    3. sort your list, so the language with the most users will be first
    4. this step is optional, but I've added a separate structure that will help us generate output and in this step, we are rewriting our input structures to output ones

    Hope this is clear for you. Let me know if you have any questions.