package nl.helixsoft.stats.impl;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import nl.helixsoft.recordstream.AbstractRecordStream;
import nl.helixsoft.recordstream.Predicate;
import nl.helixsoft.recordstream.Record;
import nl.helixsoft.recordstream.RecordMetaData;
import nl.helixsoft.recordstream.RecordStream;
import nl.helixsoft.recordstream.RecordStreamFormatter;
import nl.helixsoft.recordstream.StreamException;
import nl.helixsoft.stats.Column;
import nl.helixsoft.stats.DataFrame;
import nl.helixsoft.stats.DefaultColumnView;
import nl.helixsoft.stats.Factor;
import nl.helixsoft.stats.RecordView;
/**
* Default implementations of some methods that can be implemented
* without knowing details of the DataFrame implementation.
*/
public abstract class AbstractDataFrame implements DataFrame
{
@Override
/**
* Basic default implementation, implementing classes can override if there is a more efficient way to provide this.
*/
public Record getRow(int rowIx)
{
return new RecordView(this, rowIx);
}
@Override
/**
* Basic default implementation, implementing classes can override if there is a more efficient way to provide this.
*/
public RecordStream asRecordStream()
{
return new AbstractRecordStream() {
int pos = 0;
@Override
public RecordMetaData getMetaData() {
return AbstractDataFrame.this.getMetaData();
}
@Override
public Record getNext() throws StreamException {
return pos < getRowCount() ? getRow(pos++) : null;
}
};
}
@Override
public void toOutputStream(OutputStream os) throws IOException
{
RecordStreamFormatter.asTsv(
new PrintStream(os), asRecordStream(), null, true);
}
@Override
public int[] getColumnIndexes(String... columnNames)
{
int[] result = new int[columnNames.length];
for (int i = 0; i < columnNames.length; ++i)
{
result[i] = getColumnIndex(columnNames[i]);
}
return result;
}
@Override
public DataFrame merge(DataFrame that, String onColumn)
{
return merge(that, this.getColumnIndex(onColumn), that.getColumnIndex(onColumn));
}
@Override
public String getColumnName(int columnIndex)
{
return getColumnHeader(columnIndex).toString();
}
@Override
public Object getColumnHeader(int colIx)
{
return getColumnHeader().get(colIx);
}
@Override
public <T> Column<T> getColumn(Class<T> clazz, int columnIndex)
{
return new DefaultColumnView<T>(this, columnIndex);
}
@Override
public <T> Factor<T> getColumnAsFactor(Class<T> clazz, int columnIndex)
{
return new Factor<T>(this, columnIndex);
}
/** @inheritDocs */
@Override
public DataFrame sort(final int columnIndex)
{
List<Integer> rowIndexes = new ArrayList<Integer>();
for (int i = 0; i < getRowCount(); ++i)
{
rowIndexes.add (i);
}
Collections.sort (rowIndexes, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
Comparable c1 = (Comparable)getValueAt(o1, columnIndex);
Comparable c2 = (Comparable)getValueAt(o2, columnIndex);
if (c1 == c2) return 0; // same or both null
if (c1 == null) return -1;
if (c2 == null) return 1;
int result = c1.compareTo(c2);
if (result == 0) result = o1.compareTo(o2); // stable sorting...
return result;
}
});
return select (rowIndexes);
}
/** @inheritDocs */
@Override
public DataFrame sort(String columnName)
{
return sort(getColumnIndex(columnName));
}
public List<Record> filter(Predicate<Record> predicate)
{
List<Record> result = new ArrayList<Record>();
for (Record r : asRecordIterable())
{
if (predicate.accept(r))
{
result.add(r);
}
}
return result;
}
}