Oxford and non-Oxford comma-separated String representation for Swift Collections

Gary Bartos
3 min readMar 5, 2021

Generating a comma-separated string representation for a collection is a common programming task. It’s somewhat less common to generate a comma-separated string that includes the word “and” so that a collection can be read like a list in a normal English sentence: rather than “a, b, c, d” we might sometimes want to generate “a, b, c, and d.”

A common technique to create a comma-separated string is to append string representations of each element in a collection. If the string representation has a length greater than zero, we append a comma before appending the next element.

// non-Swift pseudocode
myArray = [element 1, element 2, ... ]
myString = ""
for element in myArray
if myString.length > 0
then myString += ", "
myString += element.toString()print(myString)

It’s easy enough to write code like that in Swift. If you’re not concerned about a few extra characters, you can simply rely on the print() function and/or string interpolation.

let letters = ["a", "b", "c"]
let numbers = [1, 0.5, -2.3, 5.7]
let mix: [Any] = ["a", 3.24, (-5, -2), ["b"]]

print(letters) // ["a", "b", "c"]
print(numbers) // [1.0, 0.5, -2.3, 5.7]
print("\(mix) mix") // ["a", 3.24, (-5, -2), ["b"]] mix

But let’s say that accessibility hints for an app feature are backed by a collection. You want VoiceOver to announce the items in the collection. For example, the speeds at which your app makes announcements are Slow, Medium, and Fast. Rather than have your iOS app say “Speeds include Slow, Medium, Fast” it’s preferable to have VoiceOver say “Speeds include Slow, Medium, and Fast.”

It’s a stylistic choice whether you choose to use the Oxford comma (“a, b, c, and d”) or the non-serial comma (“a, b, c and d”) for the String.

The code below extends Collections with two functions. The functions offer three ways of generating a comma-separated String from a Collection.

  1. Generate a comma-separated String of a Collection. For example, an Int array [1, 2, 3] becomes String representation “1, 2, 3”.
  2. Generate a comma-separated String using serial commas, and include “and” before the final element: “a, b, c, and d”
  3. Generate a comma-separated String with non-serial commas, and include “and” before the final element: “a, b, c and d”

Copy & paste the following into an Xcode 12 playground and run it. The function test() demonstrates generation of comma-separated String representations for types in Foundation, CoreGraphics, and simd frameworks.

/* CODE FOR RE-USE  */

import Foundation

extension Collection {
/// Create a comma-separated variable from a Collection.
/// - Returns: a comma-separated variable
func commaSeparated() -> String {
self.reduce("", { $0 + ($0.count > 0 ? ", " : "") + "\($1)" })
}

/// Create a comma-separated variable with "and" before the final element
/// - Parameter serialComma: if true, a comma precedes the final item in the list (a.k.a. Oxford comma or Harvard comma)
/// - Returns: a comma-separated variable
func commandSeparatedAnd(serialComma: Bool = true) -> String {
if self.isEmpty {
return String()
}
else if self.count == 1 {
return "\(self.first!)"
}

var texts = self.map( {"\($0)"} )

let final = texts.removeLast()
var r = texts.commaSeparated()

if serialComma {
r += ","
}

r += " and \(final)"
return r
}
}

/* TEST CODE */

import CoreGraphics
import simd

func test() {
var collection: [[Any]] = []
collection.append([]) //empty
collection.append(["Single"])
collection.append([2.5])
collection.append([4, 6])
collection.append(["a", "b", "c"])
collection.append([1, 5, 23, 523])
collection.append(["Oink", "Moo", "Baa", "Neigh"])
collection.append([CGVector(dx: 1.2, dy: 3.2), CGVector(dx: -1.4, dy: 0.5), CGVector(dx: 5.2, dy: -9.1) ])
collection.append([CGPoint(x: 3, y: 2), CGPoint(x: -2.7, y: 0.32)])
collection.append([simd_float2(51,50), simd_float2(31,21), simd_float2(19, 99)])

for c in collection {
print(
"""

\(c): \(c.count) elements
\(c.commaSeparated())
\(c.commandSeparatedAnd(serialComma: false))
\(c.commandSeparatedAnd(serialComma: true))
"""
)
}
}

test()

Thanks, for, reading!

--

--

Gary Bartos

Founder of Echobatix, developing assistive technology for the blind. echobatix@gmail.com