I'm trying to write an extension method for [String]
.
It seems you can't extend [String]
directly ("Type 'Element' constrained to non-protocol type 'String'"), though I came across this trick:
protocol StringType { }
extension String: StringType { }
But I still can't quite make the Swift type system happy with this:
extension Array where Element: StringType {
// ["a","b","c","d","e"] -> "a, b, c, d, or e".
func joinWithCommas() -> String {
switch count {
case 0, 1, 2:
return joinWithSeparator(" or ")
default:
return dropLast(1).joinWithSeparator(", ") + ", or " + last!
}
}
}
The joinWithSeparator
calls are "Ambiguous". I've tried everything I could think of, like using (self as! [String])
(and a bunch of similar variants), but nothing seems to work.
How can I make the Swift compiler happy with this?
edit/update
Swift 4 or later it is better to constrain the collection elements to StringProtocol which will cover Substrings as well.
extension BidirectionalCollection where Element: StringProtocol {
var joinedWithCommas: String {
guard let last = last else { return "" }
return count > 2 ? dropLast().joined(separator: ", ") + ", or " + last : joined(separator: " or ")
}
}
And if all elements are just Characters we can simply extend StringProtocol:
extension StringProtocol {
func joined(with separator: String = ",", conector: String = "") -> String {
guard let last = last else { return "" }
if count > 2 {
return dropLast().map(String.init).joined(separator: separator + " ") + separator + " " + conector + " " + String(last)
}
return map(String.init).joined(separator: " " + conector + " ")
}
}
let elements = "abc"
let elementsJoined = elements.joined() // "a, b, c"
let elementsSeparated = elements.joined(conector: "or") // "a, b, or c"
let elementsConected = elements.joined(conector: "and") // "a, b, and c"
Original answer
In Swift 3.1 (Xcode 8.3.2) you can simply extend Array constraining element type equal to String
extension Array where Element == String {
var joinedWithCommas: String {
guard let last = last else { return "" }
return count > 2 ? dropLast().joined(separator: ", ") + ", or " + last : joined(separator: " or ")
}
}
["a","b","c"].joinedWithCommas // "a, b, or c"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With