org.integratedmodelling.collections.MultidimensionalArray Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (C) 2007, 2014:
*
* - Ferdinando Villa
* - integratedmodelling.org
* - any other authors listed in @author annotations
*
* All rights reserved. This file is part of the k.LAB software suite,
* meant to enable modular, collaborative, integrated
* development of interoperable data and model components. For
* details, see http://integratedmodelling.org.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the Affero General Public License
* Version 3 or 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
* Affero General Public License for more details.
*
* You should have received a copy of the Affero General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* The license is also available at: https://www.gnu.org/licenses/agpl.html
*******************************************************************************/
package org.integratedmodelling.collections;
import java.util.ArrayList;
import java.util.Iterator;
public class MultidimensionalArray {
private ArrayList storage = new ArrayList();
MultidimensionalCursor cursor;
/**
* Aggregators are supplied to the multidimensional iterator when a dimension must be collapsed
* to size 1.
*
* @author Ferdinando
*
* @param
*/
public interface Aggregator {
public abstract void reset();
public abstract void add(T value);
public abstract T getAggregatedValue();
}
public class MultidimensionalIterator implements Iterator {
int step;
int current;
ArrayList storage;
@Override
public boolean hasNext() {
return (current + step) < storage.size();
}
@Override
public T next() {
current += step;
return current < storage.size() ? storage.get(current) : null;
}
@Override
public void remove() {
storage.remove(current);
}
protected MultidimensionalIterator(int offset, int step, int current, ArrayList data) {
this.current = offset + current;
this.step = step;
storage = data;
}
}
/**
* Return an iterator over the whole array, regardless of internal structuring. Note
* that the storage order is Fortran-like.
* @return iterator
*/
public Iterator iterator() {
return storage.iterator();
}
/**
* Return an iterator over a slice along the indicated dimension, with all other dimension
* offsets identified by the specified remaining ones. Note that the offsets passed must
* contain the exact number of dimensions, and the offsets paired to the actual dimension. The
* offset for the dimension of interest is ignored.
* @param dimension
* @param offsets
* @return iterator
*/
public MultidimensionalIterator iterator(int dimension, int... offsets) {
Triple stride = cursor.getStridedOffsets(dimension, offsets);
return new MultidimensionalIterator(stride.getFirst(), 0, stride.getThird(), storage);
}
/**
* This constructor is fairly expensive for large arrays as it preallocates the whole
* structure. The bad news is that there is no other constructor.
* @param dimensions
*/
public MultidimensionalArray(int... dimensions) {
cursor = new MultidimensionalCursor(MultidimensionalCursor.StorageOrdering.ROW_FIRST);
cursor.defineDimensions(dimensions);
storage.ensureCapacity(cursor.getMultiplicity());
}
public T get(int... indexes) {
return storage.get(cursor.getElementOffset(indexes));
}
public int size() {
return cursor.multiplicity;
}
public void set(int i, T value) {
storage.add(i, value);
}
/**
* Create a new array where the indicated dimension has been collapsed to size 1 and
* its values have been aggregated using the supplied aggregator.
*
* @param dimensionIndex
* @param aggregator
* @return collapsed array
*/
public MultidimensionalArray collapse(int dimensionIndex, Aggregator aggregator) {
int[] dims = cursor.getExtents();
dims[dimensionIndex] = 1;
MultidimensionalArray ret = new MultidimensionalArray(dims);
for (int i = 0; i < ret.size(); i++) {
aggregator.reset();
/*
* each value substituted by the aggregation of the other's data along the collapsed dimension
*/
for (Iterator it = this.iterator(dimensionIndex, this.cursor.getElementIndexes(i)); it
.hasNext();)
aggregator.add(it.next());
ret.set(i, aggregator.getAggregatedValue());
}
return ret;
}
}