Swift extension for [String]?
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"
You could follow the declaration of joinWithSeparator
(Cmd-click on it) and find that it is defined as an extension of the protocol SequenceType
instead of the type Array
.
// swift 2:
extension SequenceType where Generator.Element == String {
public func joinWithSeparator(separator: String) -> String
}
(Note: In Xcode 8 / Swift 3 if you Cmd-click on join(separator:)
you will land on Array
even if it is still implemented inside Sequence
, but that won't invalidate the idea below)
We could do the same with your function, where we extend a protocol adopted by Array instead of Array itself:
// swift 2:
extension CollectionType where
Generator.Element == String,
SubSequence.Generator.Element == String,
Index: BidirectionalIndexType
{
func joinWithCommas() -> String {
switch count {
case 0, 1, 2:
return joinWithSeparator(" or ")
default:
return dropLast(1).joinWithSeparator(", ") + ", or " + last!
}
}
}
// swift 3:
extension BidirectionalCollection where
Iterator.Element == String,
SubSequence.Iterator.Element == String
{
func joinWithCommas() -> String {
switch count {
case 0, 1, 2:
return joined(separator: " or ")
default:
return dropLast().joined(separator: ", ") + ", or " + last!
}
}
}
Note:
- we extend
CollectionType
to be able to usecount
- we constraint
Generator.Element == String
to usejoinWithSeparator
- we constraint
SubSequence.Generator.Element == String
to ensuredropLast(1)
can usejoinWithSeparator
.dropLast(1)
returns the associated typeSubSequence
. - we constraint
Index: BidirectionalIndexType
to uselast
.