Search code examples
arraysfunctional-programmingsmlsmlnjml

Print Array2 2D char array


I am trying to print a 2D char array in SML which is in the form of:

val arr = Array2.fromList [[#"a", #"b", #"c"], [#"d", #"e", #"f"], [#"g", #"h", #"i"]];

Note that the last element in each row is not an #"\n" element.

The result must be in the following form, where every row is represented in a new line:

abc
def
ghi

Is there any way to do this in SML?


Solution

  • You can iterate and print a full row at a time by using Array2.row, Array2.nRows and CharVector.tabulate:

    Array2.row   : 'a array * int -> 'a Vector.vector
    Array2.nRows : 'a array -> int
    CharVector.tabulate : int * (int -> char) -> string
    

    You could define a function app_row that takes an Array2.array and calls a function f on each row, extracted as a vector. And a function vec_to_str that takes that vector vec and converts it to a string; then print it.

    fun app_row f arr =
        let fun loop i = if i = Array2.nRows arr then ()
                         else (f (Array2.row (arr, i)); loop (i+1))
        in loop 0 end
    
    fun vec_to_str vec =
        CharVector.tabulate (Vector.length vec, fn i => Vector.sub (vec, i))
    
    fun showMatrix arr =
        app_row (fn row => print (vec_to_str row ^ "\n")) arr
    

    Trying this for size:

    - showMatrix arr;
    abc
    def
    ghi
    > val it = () : unit
    

    This solution should be less I/O intensive than e.g. using Array2.appi and print each letter one at a time. It's also slightly more complicated because it involves converting a "char Vector.vector" into a "CharVector.vector" (aka a string). (The difference between the two is subtle.)

    Still, an alternative solution akin to the solution of P. Antoniadis, but where you don't need to specify the dimensions (since they can be extracted using e.g. Array2.nCols and Array2.nRows):

    fun showMatrix arr =
        Array2.appi Array2.RowMajor (fn (_, col, c) =>
          print (str c ^ (if col + 1 = Array2.nCols arr then "\n" else "" )))
          {base=arr,row=0,col=0,nrows=NONE,ncols=NONE}