Concatenating an array of optional NSAttributedStrings Imagine you had to join together attributed strings with a separator in between them.  Which of the following methods would you use?

An extension on SequenceType with a function that takes in a separator.   Can't use any optionals in the array.

extension SequenceType where Generator.Element: NSAttributedString {
    func join(withSeparator separator: NSAttributedString) -&gt; NSAttributedString {
        var shouldAddSeparator = true
        return self.reduce(NSMutableAttributedString()) {(element, sequence) in
            if shouldAddSeparator {
            shouldAddSeparator = false
            }
            else {
                element.appendAttributedString(separator)
            }
        element.appendAttributedString(sequence)
        return element
        }
    }
}


A private function that takes in an array of optional NSAttributedString and a separator.

private func join(attributedStrings strings: [NSAttributedString?], withSeparator separator: NSAttributedString) -&gt; NSAttributedString? {
    let unwrappedStrings = strings.flatMap{$0} as [NSAttributedString]
    guard unwrappedStrings.count == strings.count else { return nil }
    let finalString = NSMutableAttributedString()
    for (index, string) in unwrappedStrings.enumerate() {
        if index == 0 {
            finalString.appendAttributedString(string)
        }
        else {
            finalString.appendAttributedString(separator)
            finalString.appendAttributedString(string)
        }
    }

    return finalString
}


Extension on _ArrayType that can take in an array of options NSAttributedString

extension _ArrayType where Generator.Element == NSAttributedString? {
    private func join(withSeparator separator: NSAttributedString) -&gt; NSAttributedString? {
        let unwrappedStrings = flatMap{$0} as [NSAttributedString]

        var shouldAddSeparator = false
        return unwrappedStrings.reduce(NSMutableAttributedString(), combine: { (string, element) in
            if shouldAddSeparator {
                string.appendAttributedString(separator)
            }
            else {
                shouldAddSeparator = true
            }
            string.appendAttributedString(element)
            return string
        })
    }
}
The second and third approach combine two tasks into one:


Extract the non-nil elements from the given array of optional
attributed strings, and
concatenate these with a given separator.


My suggestion is to separate these concerns. This rules out #2 and #3
and leaves us with your #1 approach, the extension method on SequenceType.

Another disadvantage of the extension _ArrayType  is that it uses an internal type,
so that might break in a future version of Swift.

The flatMap() method from the Swift standard library already provides a method for the first task:

let attributedStrings = optionalAttributedStrings.flatMap { $0 }


and this can be combined with your extension method by the caller:

let joined = optionalAttributedStrings.flatMap { $0 }.join(withSeparator: separator)


A user might also want to concatenate non-optional strings, which
works with the extension method:

let joined = attributedStrings.join(withSeparator: separator)


but not with the other two approaches.

Another argument for approach #1 is that it resembles
the existing method to join strings:

extension SequenceType where Generator.Element == String {
    public func joinWithSeparator(separator: String) -&gt; String
}


The method itself can be improved. The reduce() method creates a new
NSMutableAttributedString in each iteration. Better create only one
and append all elements (similar as on your join() function):

extension SequenceType where Generator.Element: NSAttributedString {

    func join(withSeparator separator: NSAttributedString) -&gt; NSAttributedString {
        let finalString = NSMutableAttributedString()
        for (index, string) in enumerate() {
            if index &gt; 0 {
                finalString.appendAttributedString(separator)
            }
            finalString.appendAttributedString(string)
        }
        return finalString
    }
}




Update: The Swift language changes constantly. For the convenience
of future readers, here is an update to Swift 4 of the above code:

extension Sequence where Element: NSAttributedString {

    func join(withSeparator separator: NSAttributedString) -&gt; NSAttributedString {
        let finalString = NSMutableAttributedString()
        for (index, string) in enumerated() {
            if index &gt; 0 {
                finalString.append(separator)
            }
            finalString.append(string)
        }
        return finalString
    }
}


Also flatMap has been renamed to compactMap:

let attributedStrings = optionalAttributedStrings.compactMap { $0 }