data(iris)
attach(iris)

# models: a list of lm models
# dp:     number of decimal places to round results to 
# ralign: 1 if output should be right align in numeric cols 
print_models <- function(models, dp=2, ralign=1) {

    ncols <- length(models)

    # assume both models have the same number of rows
    nrows <- length(models[[1]]$coefficients)
    
    coef <- matrix("0", nrows, ncols)
    CI <- matrix("0", nrows, ncols)
    t <- matrix("0", nrows, ncols)
    p <- matrix("0", nrows, ncols)
    nobs <- numeric(2)
    output.row.names <- character(nrows)
    output.col.names <- character(ncols)

    # fill the matrices with character elements
    for( i in 1:ncols ) {
        model <- models[[i]]
        model.summary <- summary(model)
        model.ci <- confint(model)
        model.coef <- coef(model.summary)
        nobs[i] <- length(model$residuals)
        
        CI.separate <- aperm(round( model.ci , dp ))
        coef.separate <- round( model.coef[,1], dp )
        t.separate <- round( model.coef[,3], dp )
        p.separate <- round( model.coef[,4], dp )
        
        output.col.names[i] <- names(attributes(model$terms)$dataClasses)[1]
        
        if(i==1) { # figure out the row names
            output.row.names <- row.names(model.coef)
        }
        
        coef[,i] <- coef.separate
        t[,i] <- t.separate
        p[,i] <- p.separate
        # deal with CI
        for(j in 1:nrows) {
            CI[j,i] <- paste0("(", paste(CI.separate[ ((j-1)*2 + 1) : (j*2) ], collapse=", "), 
                              ")")
        }
    }
    rm(model, model.summary, model.ci, model.coef)
    
    # creates matrix of character strings by column
    output.nrows <- nrows + 4
    output.ncols <- ncols + 1
    output <- matrix(c(  
        c("Variable: ", "", "", output.row.names, "Observations")
    ), output.nrows, 1, byrow=FALSE)
        
    for(i in 2:output.ncols) {
        output_col <- c("", output.col.names[i-1], "CI", CI[,i-1], "")
        output <- matrix(c(output,output_col),nrow=output.nrows)
        output_col <- c("","","t",t[,i-1],"")
        output <- matrix(c(output,output_col),nrow=output.nrows)
        output_col <- c("","","p",p[,i-1],nobs[i-1])
        output <- matrix(c(output,output_col),nrow=output.nrows)
    }
    
    output.ncols <- (output.ncols-1)*3 + 1
    # padding
    for(i in 1:output.ncols) {
        max_len <- max(nchar(output[,i]))
        for(j in 1:output.nrows) {
            if(i > 1 && ralign && j <= output.nrows) {
                output[j,i] <- paste(ifelse(j > 2 && j<output.nrows, " | ", "   "), 
                                    paste(rep(" ", max(0,max_len - nchar(output[j,i]))), collapse=""), 
                                    output[j,i])
            } else { 
                # left align
                if(j==output.nrows && i > 1) {
                    output[j,i] <- paste(paste(rep(" ", max(0,max_len - nchar(output[j,i]))), collapse=""), 
                                         output[j,i]) 
                } else {
                    output[j,i] <- paste(output[j,i], paste(rep(" ", max(0,max_len - nchar(output[j,i]))), 
                                                            collapse="") )
                }
            }
        }
    }
    
    msg_width <- sum(sapply(output[1,],nchar))
    msg <- ""
    
    for(i in 1:output.nrows ) {
        if(i==1 || i==output.nrows) {
            msg <- paste0(msg, paste(rep("=", msg_width+4), collapse=""), "\n", 
                          "| ", paste(output[i,], collapse=""), " |", "\n")
        } else {
            msg <- paste0(msg, "| ", paste(rep("-", msg_width+2), collapse=""), "\n",
                        "| ", paste(output[i,], collapse=""), " |", "\n")
        }
        
        if(i==output.nrows) {
            msg <- paste0(msg, paste(rep("=", msg_width+4), collapse=""),"\n")
        }
    }
    
    cat(msg)
}

model1 <- lm(Sepal.Length ~ Petal.Length * Petal.Width)
model2 <- lm(Sepal.Width ~ Petal.Length * Petal.Width)
model3 <- lm(Sepal.Width ~ Petal.Length * Petal.Width)
models <- list(model1,model2,model3)
print_models(models, dp=2, ralign=0)
## ========================================================================================================
## | Variable:                                                                                            |
## | ------------------------------------------------------------------------------------------------------
## |                          Sepal.Length             Sepal.Width              Sepal.Width               |
## | ------------------------------------------------------------------------------------------------------
## |                          CI             t     p   CI             t     p   CI             t     p    |
## | ------------------------------------------------------------------------------------------------------
## | (Intercept)              (4.36, 4.8)    40.89 0   (3.83, 4.24)   39.31 0   (3.83, 4.24)   39.31 0    |
## | ------------------------------------------------------------------------------------------------------
## | Petal.Length             (0.31, 0.57)   6.74  0   (-0.49, -0.25) -6.22 0   (-0.49, -0.25) -6.22 0    |
## | ------------------------------------------------------------------------------------------------------
## | Petal.Width              (-1.67, -0.81) -5.65 0   (-1.1, -0.31)  -3.51 0   (-1.1, -0.31)  -3.51 0    |
## | ------------------------------------------------------------------------------------------------------
## | Petal.Length:Petal.Width (0.12, 0.25)   5.62  0   (0.16, 0.28)   7.13  0   (0.16, 0.28)   7.13  0    |
## ========================================================================================================
## | Observations                                   150                      150                      150 |
## ========================================================================================================