22

I am trying to join the elements of a String array via the reduce function. A tried for a bit now, but I can't get what the problem exactly is. This is what I believe should do the trick. I have tried other alternatives too, but given the huge amount I will wait for some input:

var genres = ["towel", "42"]
var jointGenres : String = genres.reduce(0, combine: { $0 + "," + $1 })

Error:

..:14:44: Cannot invoke '+' with an argument list of type '(IntegerLiteralConvertible, combine: (($T6, ($T6, $T7) -> ($T6, $T7) -> $T5) -> ($T6, ($T6, $T7) -> $T5) -> $T5, (($T6, $T7) -> ($T6, $T7) -> $T5, $T7) -> (($T6, $T7) -> $T5, $T7) -> $T5) -> (($T6, ($T6, $T7) -> $T5) -> $T5, (($T6, $T7) -> $T5, $T7) -> $T5) -> $T5)'

From my understanding, $0 should be inferred as a String and $1, by combination with $0, should result as a String too. I don't know what's the deal with the type system here. Any idea?

5 Answers 5

31

Your reduce closure should probably look like this:

var jointGenres : String = genres.reduce("", combine: { $0 == "" ? $1 : $0 + "," + $1 })

This has the "" instead of 0 like you had, and makes sure that there is no extra comma in the beginning of the return value.

The original code did not work because the return type that is represented as U in documentation was originally 0 in your answer, while you are trying to add a String to it. In your case, you really want both U and T to represent Strings instead of Ints.

Sign up to request clarification or add additional context in comments.

1 Comment

I overlooked the meaning of the first parameter, thanks!
24

reduce is not a straightforward solution here since you need special handling for the first element. String's join method is better for this purpose:

let strings = ["a", "b", "c"]
let joinedString = ",".join(strings)

If you know the array is not empty there is another possible solution with reduce that also avoids conditionals:

let joinedStrings = strings[1..<strings.count].reduce(strings[0]) { $0 + "," + $1 }

1 Comment

Had to do joinedString = strings.joined(separator: ";") in Swift 4
11

If using Swift 4:

var jointGenres:String = genres.joined(separator: ",")

Comments

9

Cocoa already has a function to do this. It is marred by needing a typecast to NSArray.

var genres = ["towel", "42"]
var joinGenres = (genres as NSArray).componentsJoinedByString(",")

To my surprise, this function also can be applied to arrays of types other than String:

let ints = [1,5,9,15,29]
let listOfInts = (ints as NSArray).componentsJoinedByString(",")

Comments

2

The problem is your first argument to reduce. This is an accumulator, it's an integer literal, and it's what's passed as $0 on the first run of the block. You're asking the reduce function to add a string to this.

Instead of 0 as the accumulator argument, you should be passing "", an empty string.

This works:

var genres = ["towel", "42"]
var jointGenres : String = genres.reduce("", combine: { $0 + "," + $1 })

1 Comment

This isn't completely right, you need the ternary expression @erdekhayser is using.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.