/* * RapidMiner * * Copyright (C) 2001-2014 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.datatable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Vector; /** * A view on a parent DataTable which maps values from the parent table to other values. * Can e.g. be used to change the mapping of nominal values. * * @author Marius Helf */ public class ValueMappingDataTableView extends AbstractDataTable implements DataTableListener { public static interface MappedDataTableListener { /** * This method is called by a datatable, if its content is changed. */ public void informDataTableChange(DataTable dataTable); } private List<MappedDataTableListener> listeners = new LinkedList<MappedDataTableListener>(); private DataTable parentTable; private Vector<DataTableMappingProvider> mappings; public ValueMappingDataTableView(DataTable parentDataTable) { super(parentDataTable.getName()); this.parentTable = parentDataTable; // init mappings with nulls int columnCount = parentTable.getColumnNumber(); mappings = new Vector<DataTableMappingProvider>(columnCount); for (int i = 0; i < columnCount; ++i) { mappings.add(null); } parentTable.addDataTableListener(this); } double mapValue(double originalValue, int columnIdx) { double mappedValue = originalValue; if (mappings.elementAt(columnIdx) != null) { mappedValue = mappings.elementAt(columnIdx).mapFromParentValue(originalValue); } return mappedValue; } @Override public Iterator<DataTableRow> iterator() { return new Iterator<DataTableRow>() { int nextRow = 0; @Override public boolean hasNext() { return nextRow < getNumberOfRows(); } @Override public DataTableRow next() { DataTableRow row = getRow(nextRow); nextRow++; return row; } @Override public void remove() { throw new UnsupportedOperationException("remove() not suppported by FilterDataTable"); } }; } @Override public DataTableRow getRow(int index) { return new ValueMappingDataTableRow(parentTable.getRow(index), this); } @Override public int getNumberOfRows() { return parentTable.getNumberOfRows(); } public void setMappingProvider(int columnIdx, DataTableMappingProvider mapping) { if (mapping != mappings.elementAt(columnIdx)) { mappings.set(columnIdx, mapping); informMappedDataTableListeners(); fireEvent(); } } /* * Listener Methods */ public void addMappedDataTableListener(MappedDataTableListener listener) { this.listeners.add(listener); } public void removeMappedDataTableListewner(MappedDataTableListener listener) { this.listeners.remove(listener); } private void informMappedDataTableListeners() { for (MappedDataTableListener listener: listeners) { listener.informDataTableChange(this); } } /* * Delegating methods */ @Override public void add(DataTableRow row) { parentTable.add(row); } @Override public int getColumnIndex(String name) { return parentTable.getColumnIndex(name); } @Override public String getColumnName(int i) { return parentTable.getColumnName(i); } @Override public double getColumnWeight(int i) { return parentTable.getColumnWeight(i); } @Override public int getNumberOfColumns() { return parentTable.getNumberOfColumns(); } @Override public int getNumberOfSpecialColumns() { return parentTable.getNumberOfSpecialColumns(); } @Override public int getNumberOfValues(int column) { return parentTable.getNumberOfValues(column); } @Override public boolean isDate(int index) { return parentTable.isDate(index); } @Override public boolean isDateTime(int index) { return parentTable.isDateTime(index); } @Override public boolean isNominal(int index) { return parentTable.isNominal(index); } @Override public boolean isNumerical(int index) { return parentTable.isNumerical(index); } @Override public boolean isSpecial(int column) { return parentTable.isSpecial(column); } @Override public boolean isSupportingColumnWeights() { return parentTable.isSupportingColumnWeights(); } @Override public boolean isTime(int index) { return parentTable.isTime(index); } @Override public String mapIndex(int column, int index) { int parentIdx = index; DataTableMappingProvider mapping = mappings.elementAt(column); if (mapping != null) { if (mapping instanceof BidirectionalMappingProvider) { BidirectionalMappingProvider bidiMapping = (BidirectionalMappingProvider)mapping; parentIdx = (int)bidiMapping.mapToParentValue(index); } else { return null; } } return parentTable.mapIndex(column, parentIdx); } @Override public int mapString(int column, String value) { int index = parentTable.mapString(column, value); return (int)mapValue(index, column); } @Override public DataTable sample(int newSize) { // return parentTable.sample(newSize); return this; } @Override public void dataTableUpdated(DataTable source) { fireEvent(); } public DataTable getParent() { return parentTable; } }