0

I have an array that many elements, but two of them are important to me. Language and number

I get the info from them someting like that

_ = cities[0].language 

\\give me a string languages(it could be any languages and maybe it's nil, but all the language are written in same way (for example it's always English, not english)

and

_ = cities[0].number 
\\give me an Int

for example it gives me something like that

"English" "124324"

"French" "5634"

"English" "753"

"German" "8643"

"German" "532"

nil "6532"

I want to create a new array(let's call languageInfo), that created by filtering the cities array. I need it combine all the same lanugage together with sum of their numbers, for example the output should be something like that

for example it gives me something like that

"English" "125077"

"German" "9175"

"French" "5634"

"nil" "6532"

Could anyone tell me how to do that?

Sulthan
  • 128,090
  • 22
  • 218
  • 270
Robert
  • 315
  • 2
  • 11
  • What did you try so far that didn't work out? Can you post some code? – Michael Fourre Sep 11 '19 at 17:27
  • actually I don't know how to filter this kind of data the way that I want, I never do something like that before – Robert Sep 11 '19 at 17:51
  • I would take a look at the Array reduce function. Also, I would recommend using a Dictionary for your end result as I think that design fits better than an Array in your case. For example: `Dictionary`. If you continue to struggle with that then please post an update with some code so that we can help you on your way. https://developer.apple.com/documentation/swift/array/2298686-reduce – Michael Fourre Sep 11 '19 at 17:57

1 Answers1

0

Use reduce to sum the numbers and convert to a dictionary

As pointed out in the comments reduce can be written in a much more condensed form

let dict = cities.reduce(into: [:]) { $0[$1.language ?? "", default: 0] += $1.number }

Original version

let dict = cities.reduce(into: [String: Int](), { result, city in
    var value = city.number
    let key = city.language ?? ""
    if let sum = result[key] {
        value += sum
    }
    result[key] = value
})

Note that I use an empty string as key if language is nil, another option could be to ignore those elements

let dict2 = cities.reduce(into: [String: Int](), { result, city in
    var value = city.number
    if let key = city.language {
        if let sum = result[key] {
            value += sum
        }
        result[key] = value
    }
})

or as pointed out in the comments allow nil as key

let dict = cities.reduce(into: [String?: Int](), { result, city in
    var value = city.number
    let key = city.language
    if let sum = result[key] {
        value += sum
    }
    result[key] = value
})
Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
  • 1
    You can also just use `[String?:Int]` instead of `[String:Int]` for the dictionary type – Michael Fourre Sep 11 '19 at 18:04
  • @MichaelFourre Thanks, I am so used from java that key can not be nil. – Joakim Danielson Sep 11 '19 at 18:07
  • I really really appreciate for your help. – Robert Sep 11 '19 at 18:13
  • dear @JoakimDanielson, just a question, how can I print the most used language now and its percentage? – Robert Sep 11 '19 at 19:14
  • @Robert That is a different question really but you can sort the dictionary like [this answer](https://stackoverflow.com/a/50098633/9223839) (but use > instead of <) and get the first element in the result and to get the sum of all numbers you can use `reduce` but since this is already part of the solution you can add a new variable and add `value` to it in the current `reduce`. `if let max = sorted.first { print(max.key, 100.0 * Double(max.value)/total) }` – Joakim Danielson Sep 11 '19 at 19:35
  • Swift is a type inferred language. No need to set the resulting type explicitly. Btw Swift 4 or later you can use Dictionary Key-based subscript with default value `cities.reduce(into: [:]) { $0[$1.language, default: 0] += $1.number }` – Leo Dabus Sep 11 '19 at 20:20
  • @LeoDabus Thanks, I keep forgetting about `default` so I never got that version to work. I'll update my answer. – Joakim Danielson Sep 11 '19 at 20:37
  • Thank you so much, I really appreciated – Robert Sep 11 '19 at 23:13