unniverzal unniverzal - 23 days ago 9
Swift Question

Converting an array of strings to an array of concatenated strings

Im looking for a general and functional solution to concatenate x elements of an array to a new array of strings. Beginning from the first element, first with second, second with third and so on ... Sorry for the explanation not being very clear, but it has been hard for me to put on name on what I'm trying to achieve. So I will try to demonstrate it with examples.

1) If I'm trying to concatenate the letters 2 by 2 I'm using this function:

var letters = ["a","b","c","d","e"]

func concatenateStrings(array: [String]) -> [String] {
return array.reduce([], { (result: [String], item:String) -> [String] in
guard !result.isEmpty else {
return [item] //first item
}

return result + [ array[result.count - 1] + " \(item)"]
})
}


which produces me this result
["a", "a b", "b c", "c d", "d e"]


2) 3 by 3

func concatenateStrings(array: [String]) -> [String] {
return array.reduce([], { (result: [String], item:String) -> [String] in
guard !result.isEmpty else {
return [item] //first item
}
guard result.count != 1 else {
return result + [array[result.count - 1] + " \(item)"] // second item
}
let first = array[result.count - 2]
let second = array[result.count - 1]
return result + [ "\(first) " + second + " \(item)"]
})
}


which gives me
["a", "a b", "a b c", "b c d", "c d e"]


My question is how can I generalize this method, if for example I want to produce a new array of strings by concatenating 4 elements, 5 elements of array and so on...

Thank you, and if there is still something unclear I will happily try to be more thorough.

Answer Source

A possible solution (Swift 3+4):

func concatenateStrings(array: [String], maxLength: Int) -> [String] {

    let nestedArray = array.reduce([[String]]()) { (result, item) -> [[String]] in
        guard let last = result.last else { return [[item]] }
        return result + [Array((last + [item]).suffix(maxLength))]
    }
    return nestedArray.map { $0.joined(separator: " ") }
}

Example:

let letters = ["a","b","c","d","e"]
print(concatenateStrings(array: letters, maxLength: 3))
// ["a", "a b", "a b c", "b c d", "c d e"]

The function first creates a nested array of strings, for example

[["a"], ["a", "b"], ["a", "b", "c"], ["b", "c", "d"], ["c", "d", "e"]]

by appending the current item to the last element, and using suffix() to limit the length. Then the inner arrays are concatenated.

In Swift 4 you can also use reduce(into:) which creates less intermediate arrays, see SE-0171 Reduce with inout:

func concatenateStrings(array: [String], maxLength: Int) -> [String] {

    let nestedArray = array.reduce(into: [[String]]()) { (result, item) in
        if let last = result.last {
            result.append(Array((last + [item]).suffix(maxLength)))
        } else {
            result = [[item]]
        }
    }
    return nestedArray.map { $0.joined(separator: " ") }
}