swift-algorithms icon indicating copy to clipboard operation
swift-algorithms copied to clipboard

Consider adding a function that creates a string representation of a collection similar to Scala's mkString

Open fwgreen opened this issue 1 year ago • 0 comments

Motivation: I wanted to pretty print a 2D array (a Sudoku board) and found mapping to string and using joined(by:) fell short of what I needed.

let input = [
    [5,3,0, 0,7,0, 0,0,0],
    [6,0,0, 1,9,5, 0,0,0],
    [0,9,8, 0,0,0, 0,6,0],
  
    [8,0,0, 0,6,0, 0,0,3],
    [4,0,0, 8,0,3, 0,0,1],
    [7,0,0, 0,2,0, 0,0,6],
      
    [0,6,0, 0,0,0, 2,8,0],
    [0,0,0, 4,1,9, 0,0,5],
    [0,0,0, 0,8,0, 0,7,9],
]
/*
+-------+-------+-------+
| 5 3 0 | 0 7 0 | 0 0 0 |
| 6 0 0 | 1 9 5 | 0 0 0 |
| 0 9 8 | 0 0 0 | 0 6 0 |
+-------+-------+-------+
| 8 0 0 | 0 6 0 | 0 0 3 |
| 4 0 0 | 8 0 3 | 0 0 1 |
| 7 0 0 | 0 2 0 | 0 0 6 |
+-------+-------+-------+
| 0 6 0 | 0 0 0 | 2 8 0 |
| 0 0 0 | 4 1 9 | 0 0 5 |
| 0 0 0 | 0 8 0 | 0 7 9 |
+-------+-------+-------+
*/

My current solution is to copy Scala's mkString but I wonder if there is a better (more general and performant) way:

extension Collection {
    func makeString(_ separator: String) -> String { makeString("", separator, "") }

    func makeString(_ prefix: String, _ separator: String, _ suffix: String) -> String {
        if isEmpty { 
            return prefix + suffix 
        } else {
            return addString("", prefix, separator, suffix)
        }
    }

    private func addString(_ string: String, _ prefix: String, _ separator: String, _ suffix: String) -> String {
        var string = string
        if prefix.count != 0 { string.append(contentsOf: prefix) }
        var it = makeIterator() 
        if let start = it.next() {
            string.append(contentsOf: "\(start)")
            while let rest = it.next() {
                string.append(contentsOf: separator)
                string.append(contentsOf: "\(rest)")
            }
        }
        if suffix.count != 0 { string.append(contentsOf: suffix) }
        return string
    }
}
//This allows for something close to what is possible in Scala
func prettyString(_ sudoku: [[Int]]) -> String {
    sudoku.chunks(ofCount: 3).map { bigChunck in
        bigChunck.map { row in 
            row.chunks(ofCount: 3).map { smallChunk in 
                smallChunk.makeString(" ", " ", " ")
            }.makeString("|", "|", "|")
        }.makeString("\n")
    }.makeString("+-------+-------+-------+\n", "\n+-------+-------+-------+\n", "\n+-------+-------+-------+")
}

fwgreen avatar Apr 01 '23 05:04 fwgreen