All Downloads are FREE. Search and download functionalities are using the official Maven repository.

water.util.TwoDimTable Maven / Gradle / Ivy

There is a newer version: 3.8.2.9
Show newest version
package water.util;

import water.AutoBuffer;
import water.H2O;
import water.Iced;
import water.IcedWrapper;

import java.util.Arrays;

/**
 * Serializable 2D Table containing Strings or doubles
 * Table can be named
 * Columns and Rows can be named
 * Fields can be empty
 */
public class TwoDimTable extends Iced {
  private String     tableHeader;
  private String     tableDescription;
  private String[]   rowHeaders;
  private String[]   colHeaders;
  private String[]   colTypes;
  private String[]   colFormats;
  private IcedWrapper[][] cellValues;
  private String     colHeaderForRowHeaders;

  //public static final double emptyDouble = Double.longBitsToDouble(0x7ff8000000000100L); //also a NaN, but not Double.NaN (0x7ff8000000000000)
  public static final double emptyDouble = Double.MIN_VALUE*2; //Some unlikely value

  /**
   * Check whether a double value is considered an "empty field".
   * @param d a double value
   * @return true iff d represents an empty field
   */
  public static boolean isEmpty(final double d) {
    return Double.doubleToRawLongBits(d) == Double.doubleToRawLongBits(emptyDouble);
  }

  /**
   * Constructor for TwoDimTable (R rows, C columns)
   * @param tableHeader the table header
   * @param tableDescription the table description
   * @param rowHeaders R-dim array for row headers
   * @param colHeaders  C-dim array for column headers
   * @param colTypes  C-dim array for column types
   * @param colFormats C-dim array with printf format strings for each column
   * @param colHeaderForRowHeaders column header for row headers
   */
  public TwoDimTable(String tableHeader, String tableDescription, String[] rowHeaders, String[] colHeaders, String[] colTypes,
                     String[] colFormats, String colHeaderForRowHeaders) {
    if (tableHeader == null)
      tableHeader = "";
    if (tableDescription == null)
      tableDescription = "";
    this.colHeaderForRowHeaders = colHeaderForRowHeaders;

    if (rowHeaders == null)
      throw new IllegalArgumentException("rowHeaders is null");
    else {
      for (int r = 0; r < rowHeaders.length; ++r)
        if (rowHeaders[r] == null)
          rowHeaders[r] = "";
    }

    if (colHeaders == null)
      throw new IllegalArgumentException("colHeaders is null");
    else {
      for (int c = 0; c < colHeaders.length; ++c)
        if (colHeaders[c] == null)
          colHeaders[c] = "";
    }

    final int rowDim = rowHeaders.length;
    final int colDim = colHeaders.length;

    if (colTypes == null) {
      colTypes = new String[colDim];
      Arrays.fill(colTypes, "string");
    }
    else if (colTypes.length != colDim)
      throw new IllegalArgumentException("colTypes must have the same length as colHeaders");
    else {
      for (int c = 0; c < colDim; ++c) {
        colTypes[c] = colTypes[c].toLowerCase();
        if (!(colTypes[c].equals("double") || colTypes[c].equals("float") || colTypes[c].equals("int") ||
            colTypes[c].equals("long") || colTypes[c].equals("string")))
          throw new IllegalArgumentException("colTypes values must be one of \"double\", \"float\", \"int\", \"long\", or \"string\"");
      }
    }

    if (colFormats == null) {
      colFormats = new String[colDim];
      Arrays.fill(colFormats, "%s");
    }
    else if (colFormats.length != colDim)
      throw new IllegalArgumentException("colFormats must have the same length as colHeaders");

    this.tableHeader = tableHeader;
    this.tableDescription = tableDescription;
    this.rowHeaders = rowHeaders;
    this.colHeaders = colHeaders;
    this.colTypes = colTypes;
    this.colFormats = colFormats;
    this.cellValues = new IcedWrapper[rowDim][colDim];
  }

  /**
   * Constructor for TwoDimTable (R rows, C columns)
   * @param tableHeader the table header
   * @param tableDescription the table description
   * @param rowHeaders R-dim array for row headers
   * @param colHeaders  C-dim array for column headers
   * @param colTypes  C-dim array for column types
   * @param colFormats C-dim array with printf format strings for each column
   * @param colHeaderForRowHeaders column header for row headers
   * @param strCellValues String[R][C] array for string cell values, can be null (can provide String[R][], for example)
   * @param dblCellValues double[R][C] array for double cell values, can be empty (marked with emptyDouble - happens when initialized with double[R][])
   */
  public TwoDimTable(String tableHeader, String tableDescription, String[] rowHeaders, String[] colHeaders, String[] colTypes,
                     String[] colFormats, String colHeaderForRowHeaders, String[][] strCellValues, double[][] dblCellValues) {
    this(tableHeader, tableDescription, rowHeaders, colHeaders, colTypes, colFormats, colHeaderForRowHeaders);

    assert (isEmpty(emptyDouble));
    assert (!Arrays.equals(new AutoBuffer().put8d(emptyDouble).buf(), new AutoBuffer().put8d(Double.NaN).buf()));

    final int rowDim = rowHeaders.length;
    final int colDim = colHeaders.length;

    for (int c = 0; c < colDim; ++c) {
      if (colTypes[c].equalsIgnoreCase("string")) {
        for (String[] vec : strCellValues) {
          if (vec == null)
            throw new IllegalArgumentException("Null string in strCellValues");
          if (vec.length != colDim)
            throw new IllegalArgumentException("Each row in strCellValues must have the same length as colHeaders");
        }
        break;
      }
    }
    for (int c = 0; c < colDim; ++c) {
      if (!colTypes[c].equalsIgnoreCase("string")) {
        for (double[] vec : dblCellValues) {
          if (vec.length != colDim)
            throw new IllegalArgumentException("Each row in dblCellValues must have the same length as colHeaders");
        }
        break;
      }
    }

    for (int r = 0; r < rowDim; ++r) {
      for (int c = 0; c < colDim; ++c) {
        if (strCellValues[r] != null && strCellValues[r][c] != null &&
            dblCellValues[r] != null && !isEmpty(dblCellValues[r][c]))
          throw new IllegalArgumentException("Cannot provide both a String and a Double at row " + r + " and column " + c + ".");
      }
    }

    for (int c = 0; c < colDim; ++c) {
      switch (colTypes[c]) {
        case "double":
        case "float":
          for (int r = 0; r < rowDim; ++r)
            set(r, c, dblCellValues[r][c]);
          break;
        case "int":
          for (int r = 0; r < rowDim; ++r)
            set(r, c, (int) dblCellValues[r][c]);
          break;
        case "long":
          for (int r = 0; r < rowDim; ++r)
            set(r, c, (long) dblCellValues[r][c]);
          break;
        case "string":
          for (int r = 0; r < rowDim; ++r)
            set(r, c, strCellValues[r][c]);
          break;
        default:
          throw new IllegalArgumentException("Column type " + colTypes[c] + " is not supported.");
      }
    }
  }

  /**
   * Accessor for table cells
   * @param row a row index
   * @param col a column index
   * @return Object (either String or Double or Float or Integer or Long)
   */
  public Object get(final int row, final int col) { return cellValues[row][col] == null ? null : cellValues[row][col].get(); }

  public String getTableHeader() { return tableHeader; }

  public String getTableDescription() { return tableDescription; }

  public String[] getRowHeaders() { return rowHeaders; }

  public String[] getColHeaders() { return colHeaders; }

  public String getColHeaderForRowHeaders() { return colHeaderForRowHeaders; }

  public String[] getColTypes() { return colTypes; }

  public String[] getColFormats() { return colFormats; }

  public IcedWrapper[][] getCellValues() { return cellValues; }

  /**
   * Get row dimension
   * @return int
   */
  public int getRowDim() { return rowHeaders.length; }

  /**
   * Get col dimension
   * @return int
   */
  public int getColDim() { return colHeaders.length; }

  /**
   * Setter for table cells
   * @param row a row index
   * @param col a column index
   * @param o Object value
   */
  public void set(final int row, final int col, final Object o) {
    if (o == null) {
      cellValues[row][col] = null;
      return;
    }

    if (colTypes[col].equals("double"))
      cellValues[row][col] = new IcedWrapper(new Double(o.toString()));
    else if (colTypes[col].equals("float"))
      cellValues[row][col] = new IcedWrapper(new Float(o.toString()));
    else if (colTypes[col].equals("int"))
      cellValues[row][col] = new IcedWrapper(new Integer(o.toString()));
    else if (colTypes[col].equals("long"))
      cellValues[row][col] = new IcedWrapper(new Long(o.toString()));
    else
      cellValues[row][col] = new IcedWrapper(o);
  }

  /**
   * Print table to String, using 2 spaces for padding between columns
   * @return String containing the ASCII version of the table
   */
  public String toString() {
    return toString(2, true);
  }
  /**
   * Print table to String, using user-given padding
   * @param pad number of spaces for padding between columns
   * @return String containing the ASCII version of the table
   */
  public String toString(final int pad) {
    return toString(pad, true);
  }

  private static int PRINTOUT_ROW_LIMIT = 20;
  private boolean skip(int row) {
    assert(PRINTOUT_ROW_LIMIT % 2 == 0);
    if (getRowDim() <= PRINTOUT_ROW_LIMIT) return false;
    if (row <= PRINTOUT_ROW_LIMIT/2) return false;
    if (row >= getRowDim()-PRINTOUT_ROW_LIMIT/2) return false;
    return true;
  }
  /**
   * Print table to String, using user-given padding
   * @param pad number of spaces for padding between columns
   * @param full whether to print the full table (otherwise top 5 and bottom 5 rows only)
   * @return String containing the ASCII version of the table
   */
  public String toString(final int pad, boolean full) {
    if (pad < 0)
      throw new IllegalArgumentException("pad must be a non-negative integer");

    final int rowDim = getRowDim();
    final int colDim = getColDim();

    final int actualRowDim = full ? rowDim : Math.min(PRINTOUT_ROW_LIMIT+1, rowDim);

    final String[][] cellStrings = new String[actualRowDim + 1][colDim + 1];
    for (String[] row: cellStrings)
      Arrays.fill(row, "");

    cellStrings[0][0] = colHeaderForRowHeaders != null ? colHeaderForRowHeaders : "";
    int row = 0;
    for (int r = 0; r < rowDim; ++r) {
      if (!full && skip(r)) continue;
      cellStrings[row+1][0] = rowHeaders[r];
      row++;
    }
    for (int c = 0; c < colDim; ++c)
      cellStrings[0][c+1] = colHeaders[c];

    for (int c = 0; c < colDim; ++c) {
      final String formatString = colFormats[c];
      row = 0;
      for (int r = 0; r < rowDim; ++r) {
        if (!full && skip(r)) continue;
        switch (colTypes[c]) {
          case "double":
            cellStrings[row + 1][c + 1] = get(r,c) == null || isEmpty((Double)get(r,c)) ? "" : String.format(formatString, (Double)cellValues[r][c].get());
            break;
          case "float":
            cellStrings[row + 1][c + 1] = get(r,c) == null ? "" : String.format(formatString, (Float)cellValues[r][c].get());
            break;
          case "int":
            cellStrings[row + 1][c + 1] = get(r,c) == null ? "" : String.format(formatString, (Integer)cellValues[r][c].get());
            break;
          case "long":
            cellStrings[row + 1][c + 1] = get(r,c) == null ? "" : String.format(formatString, (Long)cellValues[r][c].get());
            break;
          default:
            if( get(r,c) != null )
              cellStrings[row+1][c+1] = String.format(formatString, cellValues[r][c]);
            break;
        }
        row++;
      }
    }

    final int[] colLen = new int[colDim + 1];
    for (int c = 0; c <= colDim; ++c) {
      for (int r = 0; r <= actualRowDim; ++r) {
        colLen[c] = Math.max(colLen[c], cellStrings[r][c].length());
      }
    }

    final StringBuilder sb = new StringBuilder();
    if (tableHeader.length() > 0) {
      sb.append(tableHeader);
    }
    if (tableDescription.length() > 0) {
      sb.append(" (").append(tableDescription).append(")");
    }
    sb.append(":\n");
    for (int r = 0; r <= actualRowDim; ++r) {
      int len = colLen[0];
      if (actualRowDim != rowDim && r - 1 == PRINTOUT_ROW_LIMIT/2) {
        assert(!full);
        sb.append("---");
      } else {
        if (len > 0)
          sb.append(String.format("%" + colLen[0] + "s", cellStrings[r][0]));
        for (int c = 1; c <= colDim; ++c) {
          len = colLen[c];
          if (len > 0)
            sb.append(String.format("%" + (len + pad) + "s", cellStrings[r][c].equals("null") ? "" : cellStrings[r][c]));
        }
      }
      sb.append("\n");
    }

   return sb.toString();
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy