/**
  * Returns the object at row # row
  *
  * @param row the row number
  * @return the object at row # row. if no such object exists - returns null.
  */
 public Object getObject(int row) {
   if (elements.containsKey(row)) {
     return elements.get(row);
   } else {
     return SparseDefaultValues.getDefaultObject();
   }
 }
  /**
   * sorts the elements in this column so that the rows that were originally valid remain valid
   * after sorting Note - sort() supports only Comparable Objects or char arrays or byte arrays.
   * using sort with objects different than the above will throw an exception.
   */
  public void sort() {
    VIntIntHashMap newOrder = getNewOrder();
    elements = (VIntObjectHashMap) elements.reorder(newOrder);

    missing = missing.reorder(newOrder);
    empty = empty.reorder(newOrder);
  }
  /**
   * If the item at pos is a Number, return its int value. Otherwise if the item is a char[] or any
   * other type of Object, convert the item to a String and return its int value.
   *
   * @param row the row number
   * @return the int value of the item at row # row. If no such value exists returns a value
   *     signifying the position is empty, as defined by SparseIntColumn.
   */
  public int getInt(int row) {
    Object obj = elements.get(row);
    if (obj != null && isDataNumeric(row)) {
      return SparseIntColumn.toInt(obj);
    }

    return SparseDefaultValues.getDefaultInt();
  }
  /**
   * If the item at pos is a Number, return its float value. Otherwise if the item is a char[] or
   * any other type of Object, convert the item to a String and return its float value.
   *
   * @param row the row number
   * @return the float value of the item at row # row. if no such item exists or if the data is not
   *     numeric - returns a value signifying the position is empty, as defined by
   *     SparseFloatColumn.
   */
  public float getFloat(int row) {
    Object obj = elements.get(row);
    if (obj != null && isDataNumeric(row)) {
      return SparseFloatColumn.toFloat(obj);
    }

    return (float) SparseDefaultValues.getDefaultDouble();
  }
  /**
   * If the item at pos is a Number, return its double value. Otherwise if the item is a char[] or
   * any other type of Object, convert the item to a String and return its double value by calling
   * Double.parseDouble()
   *
   * @param row the row number
   * @return the double value of the item at row # row. if no such item exists returns a value
   *     signifying the position is empty, as defined by SparseDoubleColumn.
   */
  public double getDouble(int row) {
    Object obj = elements.get(row);
    if (obj != null && isDataNumeric(row)) {
      return SparseDoubleColumn.toDouble(obj);
    }

    return SparseDefaultValues.getDefaultDouble();
  }
  /**
   * Retrun the value at row #<code>row</code> as a char.
   *
   * @param row the row number
   * @return the item at row as a char, if no such item exists return a value signifying the
   *     position is empty, as defined by SparseCharColumn.
   */
  public char getChar(int row) {
    Object obj = elements.get(row);
    if (obj != null) {
      return SparseCharColumn.toChar(obj);
    }

    return SparseDefaultValues.getDefaultChar();
  }
  /**
   * If the item at pos is a Number, return its long value. Otherwise if the item is a char[] or any
   * other type of Object, convert the item to a String and return its long value.
   *
   * @param row the row number
   * @return the long value of the item at row # row. If no such value exists returns a value
   *     signifying the position is empty, as defined by SparseLongColumn.
   */
  public long getLong(int row) {
    Object obj = elements.get(row);
    if (obj != null && isDataNumeric(row)) {
      return SparseLongColumn.toLong(obj);
    }

    return (long) SparseDefaultValues.getDefaultInt();
  }
  /**
   * If the item at pos is a Number, return its short value. Otherwise if the item is a char[] or
   * any other type of Object, convert the item to a String and return its short value.
   *
   * @param row the row number
   * @return the short value of the item at row number row. If no such value exists returns a value
   *     signifying the position is empty, as defined by SparseShortColumn.
   */
  public short getShort(int row) {
    Object obj = elements.get(row);
    if (obj != null && isDataNumeric(row)) {
      return SparseShortColumn.toShort(obj);
    }

    return (short) SparseDefaultValues.getDefaultInt();
  }
  /**
   * If the object at row # row is a byte array, returns the first item in the array. else - returns
   * a representation of this object as a bytes array.
   *
   * @param row the row number
   */
  public byte getByte(int row) {
    Object obj = elements.get(row);
    if (obj != null && isDataNumeric(row)) {
      return SparseByteColumn.toByte(obj);
    }

    return SparseDefaultValues.getDefaultByte();
  }
  /**
   * Returns the item at pos as a boolean. If the item is a Boolean, return its boolean value,
   * otherwise construct a new Boolean by calling the toString() method on the item and return its
   * boolean value.
   *
   * @param row the row number
   * @return the item as pos as a boolean value. If no such item exists returns false.
   */
  public boolean getBoolean(int row) {
    Object obj = elements.get(row);
    if (obj != null) {
      return SparseBooleanColumn.toBoolean(obj);
    }

    return SparseDefaultValues.getDefaultBoolean();
  }
  /** Returns the internal representation of this column. */
  public Object getInternal() {
    int max_index = -1;
    Object[] internal = null;
    int[] keys = elements.keys();

    for (int i = 0; i < keys.length; i++) {
      if (keys[i] > max_index) {
        max_index = keys[i];
      }
    }

    internal = new Object[max_index + 1];
    for (int i = 0; i < max_index + 1; i++) {
      internal[i] = SparseDefaultValues.getDefaultObject();
    }

    for (int i = 0; i < keys.length; i++) {
      internal[keys[i]] = elements.get(keys[i]);
    }

    return internal;
  }
  /**
   * returns a subset of this column with entried from rows indicated by <code>indices</code>.
   *
   * @param indices row numbers to include in the returned subset.
   * @return a subset of this column, including rows indicated by <code>indices</code>.
   */
  public Column getSubset(int[] indices) {
    SparseObjectColumn retVal = new SparseObjectColumn(indices.length);
    for (int i = 0; i < indices.length; i++) {
      if (elements.containsKey(indices[i])) {

        // XIAOLEI
        // retVal.setObject(getObject(indices[i]), indices[i]);
        retVal.setObject(getObject(indices[i]), i);
      }
    }
    super.getSubset(retVal, indices);

    return retVal;
  }
 /**
  * Swaps the values between 2 rows. If there is no data in row #<code>pos1</code> then nothing is
  * stored in row #<ocde>pos2</code>, and vice versia.
  *
  * @param pos1 - the row number of first item to be swaped
  * @param pos2 - the row number of second item to be swaped
  */
 public void swapRows(int pos1, int pos2) {
   if (pos1 == pos2) {
     return;
   }
   Object obj1 = elements.remove(pos1);
   Object obj2 = elements.remove(pos2);
   if (obj1 != null) {
     setObject(obj1, pos2);
   }
   if (obj2 != null) {
     setObject(obj2, pos1);
   }
   missing.swapRows(pos1, pos2);
   empty.swapRows(pos1, pos2);
 }
  /**
   * Returns the valid values in rows <codE>begin</code> through <codE>end</code>
   *
   * @param begin row number from to begin retrieving of values
   * @param end last row number in the section from which values are retrieved.
   * @return only valid values from rows no. <code>begin</code> through <codE>end</code>, sorted.
   */
  protected Object[] getValuesInRange(int begin, int end) {

    if (end < begin) {
      Object[] retVal = {};
      return retVal;
    }

    int[] indices = VHashService.getIndicesInRange(begin, end, elements);
    Object[] values = new Object[indices.length];
    for (int i = 0; i < indices.length; i++) {
      values[i] = elements.get(indices[i]);
    }
    toComparableArray(values);

    Arrays.sort(values);
    return values;
  }
  /**
   * Returns a SparseObjectColumn that holds only the data from rows <code>
   * pos</code> through <code>pos+len</code>
   *
   * @param pos the row number which is the beginning of the subset
   * @param len number of consequetive rows after <code>pos</code> that are to be included in the
   *     subset.
   * @return a SparseObjectColumn with the data from rows <code>pos</code> through <code>pos+len
   *     </code>
   */
  public Column getSubset(int pos, int len) {
    SparseObjectColumn subCol = new SparseObjectColumn();
    subCol.elements = (VIntObjectHashMap) elements.getSubset(pos, len);
    getSubset(subCol, pos, len);

    return subCol;
    /*
        //the map to hold the data of the subset
         VIntObjectHashMap tempMap = new VIntObjectHashMap(len);
         //for each Object from pos till pos+len
         for (int i=0; i<len; i++)
    //if a value is mapped to current inspected row number
    if(elements.containsKey(pos+i))
     //put it in the new map
     tempMap.put(pos+i, getObject(pos+i));
        SparseObjectColumn subCol = new SparseObjectColumn();   //the returned value
        super.copy(subCol);     //copying general attributes
        //activating copy method in order to have a deep copy of the subset
        subCol.elements = tempMap.copy();    //linking the data to the returned value
         return subCol;
    */
  }
 /**
  * Reorders the data stored in this column in a new column. Does not change this column.
  *
  * <p>Algorithm: copy this column into the returned vlaue. for each pair (key, val) in <code>
  * newOrder</code>, if val is a valid row in this column, put the value mapped to it in row no.
  * key in the returned values.
  *
  * @param newOrder - an int to int hashmap, defining the new order for the returned column.
  * @return a SparseObjectColumn ordered according to <code>newOrder</code>.
  */
 public Column reorderRows(VIntIntHashMap newOrder) {
   SparseObjectColumn retVal = new SparseObjectColumn();
   retVal.elements = (VIntObjectHashMap) elements.reorder(newOrder);
   reorderRows(retVal, newOrder);
   return retVal;
 }
 /**
  * Sets the item at row #<code>pos</code> to be <code>newEntry</code>
  *
  * @param newEntry - the object to be assigned to row #<code>pos</code> param pos - the row number
  *     to be set.
  */
 public void setObject(Object newEntry, int pos) {
   elements.remove(pos);
   elements.put(pos, newEntry);
 }
 /**
  * If the entry at pos is a byte[], return the byte[], otherwise convert the Object to a byte[] by
  * calling ByteUtils.writeObject()
  *
  * @param row the row number
  * @return the entry at pos as a byte[]. if no such entry exists returns null
  */
 public byte[] getBytes(int row) {
   Object obj = elements.get(row);
   return SparseByteArrayColumn.toByteArray(obj);
 }
 /**
  * removes a row from this column and returns the removed item as an object
  *
  * @param row - the row number to be removed.
  * @return - the removed object.
  */
 public Object removeRow(int row) {
   return elements.remove(row);
 }
 /**
  * Returns the value at row # row, represented as a String.
  *
  * @param row the row number
  * @return a String Object representing the value at row # row. if no such value exists returns
  *     null
  */
 public String getString(int row) {
   Object obj = elements.get(row);
   return SparseStringColumn.toStringObject(obj);
 }
 /**
  * If the item at pos is a char[], return it. Otherwise converts it to a char[] using
  * SparseCharArrayColumn's method.
  *
  * @param row the row number
  * @return the value at row # row represented with a chars array. If no such value exists returns
  *     null.
  */
 public char[] getChars(int row) {
   Object obj = elements.get(row);
   return SparseCharArrayColumn.toCharArray(obj);
 }