Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between combining array by using reduce or joined?

Consider the following array -of strings-:

let arrayStrings = ["H", "e", "l", "l", "o"]

For combining its elements (to get "Hello" as single String), we could:

reduce it:

let reducedString = arrayStrings.reduce("", { $0 + $1 }) // "Hello"

Or join it:

let joinedString = arrayStrings.joined() // "Hello"

Both would return "Hello" String as output.

However, what is the logic to keep in mind to determine what is the better choice for such a process? What is the difference when comparing based on the performance?

like image 732
Ahmad F Avatar asked Jan 02 '23 19:01

Ahmad F


2 Answers

There are two reasons why joined is a better choice than reduce:

  1. Readability

    If you want to join multiple strings into one string, why would you use reduce, with manual concatenation? If there is a specific function for the task you want to do, use it. When reading the code, it's easier to understand joined than reduce.

  2. Performance

    joined for String can be implemented better than reduce. It does not have to be but it can. reduce operates on one element at a time, without knowledge about the other elements, with many temporary variables passed around. joined has the knowledge of the entire sequence and it knows that the operation is always the same, therefore it can optimize. It can even use the internal structure of String. See String.joined implementation.

In summary, always use the more specific implementation. Note that the performance reason above is the less important one.

like image 167
Sulthan Avatar answered Jan 05 '23 16:01

Sulthan


Update The previous results were obtained by running an iOS app on the simulator. Running the app on a real device, or running the code from a MacOS command line app gives similar results to ones @Sulthan mentioned.


Interestingly enough, reduce gave better results on my machine:

func benchmark(_ label: String, times: Int = 100000, _ f: () -> Void) {
    let start = CACurrentMediaTime()
    (0..<times).forEach { _ in f() }
    let end = CACurrentMediaTime()
    print("\(label) took \(end-start)")
}

let arrayStrings = ["H", "e", "l", "l", "o"]
benchmark("reduce", { _ = arrayStrings.reduce("", +) } )
benchmark("join", { _ = arrayStrings.joined() })

The results were around the following numbers when run from the main method of a typical iOS app, build in Debug mode:

reduce took 0.358474982960615
join took 0.582276367989834

Same app, built in Release mode, gave the same order of results:

reduce took 0.126910287013743
join took 0.0291724550188519

I ran the benchmarks multiple times, and reduce performed better in all cases. The difference is not that big though, so unless your string operations are critical in regards to performance, I'd recommend using joined, that method carries more semantical value, it better transmits the intent.

like image 39
Cristik Avatar answered Jan 05 '23 15:01

Cristik