Reputation: 1474
for example:
var a = [1, 2, 3] // Ints
var s = ",".join(a) // EXC_BAD_ACCESS
Is it possible to make the join function return "1,2,3" ?
Extend Int (or other custom types) to conform to some protocols ?
Upvotes: 21
Views: 20073
Reputation: 11
A Swift 3 solution
public extension Sequence where Iterator.Element: CustomStringConvertible {
func joined(seperator: String) -> String {
return self.map({ (val) -> String in
"\(val)"
}).joined(separator: seperator)
}
}
Upvotes: 1
Reputation: 4133
From Xcode 7.0 beta 6 in Swift 2 now you should use [String].joinWithSeparator(",")
.
In your case you still need to change Int to String type, therefore I added map()
.
var a = [1, 2, 3] // [1, 2, 3]
var s2 = a.map { String($0) }.joinWithSeparator(",") // "1,2,3"
From Xcode 8.0 beta 1 in Swift 3 code slightly changes to
[String].joined(separator: ",")
.
var s3 = a.map { String($0) }.joined(separator: ",") // "1,2,3"
Upvotes: 43
Reputation: 165
And just to make your life more complete, starting from Xcode 8.0 beta 1 in Swift 3 you should NOW use [String].joined(separator: ",")
.
This is the new "ed/ing" naming rule for Swift APIs:
Name functions and methods according to their side-effects
- Those without side-effects should read as noun phrases, e.g. x.distance(to: y), i.successor().
- Those with side-effects should read as imperative verb phrases, e.g., print(x), x.sort(), x.append(y).
- Name Mutating/nonmutating method pairs consistently. A mutating method will often have a nonmutating variant with similar semantics, but that returns a new value rather than updating an instance in-place. Swift: API Design Guidelines
Upvotes: 10
Reputation: 72750
The simplest way is a variation of @BryanChen's answer:
",".join(a.map { String($0) } )
Upvotes: 6
Reputation: 46578
try this
var a = [1, 2, 3] // Ints
var s = ",".join(a.map { $0.description })
or add this extension
extension String {
func join<S : SequenceType where S.Generator.Element : Printable>(elements: S) -> String {
return self.join(map(elements){ $0.description })
}
// use this if you don't want it constrain to Printable
//func join<S : SequenceType>(elements: S) -> String {
// return self.join(map(elements){ "\($0)" })
//}
}
var a = [1, 2, 3] // Ints
var s = ",".join(a) // works with new overload of join
join is defined as
extension String {
func join<S : SequenceType where String == String>(elements: S) -> String
}
which means it takes a sequence of string, you can't pass a sequence of int to it.
Upvotes: 29
Reputation: 10224
Even if you can't make join work for custom types, there's an easy workaround. All you have to do is define a method on your class (or extend a built-in class) to return a string, and then map that into the join.
So, for example, we could have:
extension Int {
func toString() -> String {
return "\(self)" // trivial example here, but yours could be more complex
}
Then you can do:
let xs = [1, 2, 3]
let s = join(xs.map { $0.toString() })
I wouldn't recommend using .description
for this purpose, as by default it will call .debugDescription
, which is not particularly useful in production code.
In any case, it would be better to provide an explicit method for transforming into a string suitable for joining, rather than relying on a generic 'description' method which you may change at a later date.
Upvotes: 3