String: what's the best way to insert "\n" between characters?

// want to insert "\n" between characters
var str = "Hello, playground"

var asArray = Array(str)      // must first convert to [Character]?

// Cannot do this:
// let vertical1 = asArray.joined(separator: "\n")   // Compile error:  Referencing instance method 'joined(separator:)' on 'BidirectionalCollection' requires the types 'String.Element' (aka 'Character') and 'String' be equivalent


// There must be a better way?
let vertical2 = asArray.map { "\($0)" }.joined(separator: "\n")

print(vertical2)

Is there a short one liner to do this?

[Edit: Sorry for the noise. I totally miss‐understood what you are trying to to.]

I could have sworn a String‐returning overload for str.joined(separator:) existed. Maybe I defined it in an extension of my own and forgot. [Edit: It does. See here.]

In any case, you can at least do this:

let vertical = String(str.joined(separator: "\n"))

This is because the generic function returns a special collection that just cleverly iterates out of the original in a different order instead of allocating new space. So the line above manually converts that collection back into a separately allocated String.

You don't need the intermediate asArray to accomplish this. You can apply your map directly on the string.

let vertical = str.map { "\($0)" }.joined(separator: "\n")
1 Like

I think you can do:

let vertical = str.map(String.init(describing:)).joined(separator: "\n")

here.

1 Like

Okay, I see what you did. So this is a shorter one using .init(_ c: Character):

str.map(String.init).joined(separator: "\n")

I haven't memorized all the initializers, but you may have to add the signature if there are multiple initializers that could match. The one I used can be used for all sequences of a streamable type.

It worked, I tried it.

So either one works:

str.map(String.init).joined(separator: "\n")    // 1
str.map { "\($0)" }.joined(separator: "\n")     // 2

not sure which is better, // 2 is one character shorter and seems to be clearer.

Note that map will still create an intermediary array and return it. You can avoid the intermediary array entirely by using lazy:

str.lazy.map { "\($0)" }.joined(separator: "\n")
1 Like

Wish there is "auto lazy" like we have automatic reference count: can the compiler insert lazy?