Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package local.laer.app.knapsack.support; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.databind.util.Converter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; import java.util.logging.Logger; import static java.util.stream.Collectors.toList; import local.laer.app.knapsack.domain.Cell; import local.laer.app.knapsack.domain.ImmutablePosition; import local.laer.app.knapsack.domain.Position; import local.laer.app.knapsack.domain.support.Matrix; import static local.laer.app.knapsack.support.IntFunctions.col; import static local.laer.app.knapsack.support.IntFunctions.partial; import local.laer.app.knapsack.support.matrix.IntMatrix; /** * * @author Lars Eriksson (larsq.eriksson@gmail.com) */ @JsonSerialize(converter = OffsetIntMatrix.JsonConverter.class) public class OffsetIntMatrix implements IntMatrix { private final static Logger LOG = Logger.getLogger(OffsetIntMatrix.class.getPackage().getName()); public static class JsonConverter implements Converter<OffsetIntMatrix, Matrix> { private static Matrix.Stripe defineRowStripe(OffsetIntMatrix matrix, int row) { Matrix.Stripe stripe = new Matrix.Stripe(); stripe.setDirection(Matrix.Direction.Row); stripe.setOffset(new ImmutablePosition(row, matrix.colOffset)); int[] rowData = matrix.extractRow(matrix.colOffset, matrix.cols(), row); String[] converted = Arrays.stream(rowData).mapToObj(String::valueOf).collect(toList()) .toArray(new String[0]); stripe.setData(converted); return stripe; } @Override public Matrix convert(OffsetIntMatrix value) { List<Matrix.Stripe> stripes = new ArrayList<>(); value.consume( partial(col(value.colOffset), cell -> stripes.add(defineRowStripe(value, cell.getRow())))); Matrix m = new Matrix(); m.setContent(stripes.toArray(new Matrix.Stripe[stripes.size()])); m.setDefaultValue(value.defaultValue); return m; } @Override public JavaType getInputType(TypeFactory typeFactory) { return typeFactory.constructType(OffsetIntMatrix.class); } @Override public JavaType getOutputType(TypeFactory typeFactory) { return typeFactory.constructType(Matrix.class); } } protected int[] extractCol(int lowerRowIndexInclusive, int nRows, int col) { int[] data = new int[nRows]; for (int i = 0; i < nRows; i++) { data[i] = getInt(i + lowerRowIndexInclusive, col); } return data; } protected int[] extractRow(int lowerColIndexInclusive, int nCols, int row) { int[] data = new int[nCols]; for (int i = 0; i < nCols; i++) { data[i] = getInt(row, i + lowerColIndexInclusive); } return data; } protected static boolean within(int n, int lowerInclusive, int size) { int upperExclusive = lowerInclusive + size; return lowerInclusive <= n && n < upperExclusive; } protected static int[][] copy(int[][] value) { int[][] clone = new int[value.length][value[0].length]; for (int i = 0; i < clone.length; i++) { System.arraycopy(value[i], 0, clone[i], 0, value[i].length); } return clone; } private final int rowOffset; private final int colOffset; private final int[][] value; private final int defaultValue; protected int lowerRow() { return rowOffset; } protected int lowerCol() { return colOffset; } protected OffsetIntMatrix(int row, int col, int[][] value, Integer defaultValue) { this.rowOffset = row; this.colOffset = col; this.value = copy(value); this.defaultValue = (defaultValue == null) ? 0 : defaultValue; } public OffsetIntMatrix(int row, int col, int rows, int cols, Integer defaulValue) { this.rowOffset = row; this.colOffset = col; this.value = new int[rows][cols]; this.defaultValue = (defaulValue == null) ? 0 : defaulValue; } public OffsetIntMatrix transform(Function<Cell<Integer>, Integer> callback) { OffsetIntMatrix matrix = new OffsetIntMatrix(rowOffset, colOffset, value, defaultValue); matrix.mutableTransform(callback); return matrix; } public void consume(Consumer<Cell<Integer>> callback) { SimpleCell<Integer> cell = new SimpleCell<>(); for (int row = 0; row < rows(); row++) { for (int col = 0; col < cols(); col++) { cell.col = col + colOffset; cell.row = row + rowOffset; cell.value = value[row][col]; callback.accept(cell); } } } protected void mutableTransform(Function<Cell<Integer>, Integer> callback) { SimpleCell<Integer> cell = new SimpleCell<>(); for (int row = 0; row < rows(); row++) { for (int col = 0; col < cols(); col++) { cell.col = col + colOffset; cell.row = row + rowOffset; cell.value = value[row][col]; Integer newValue = callback.apply(cell); value[row][col] = (newValue == null) ? defaultValue : newValue; } } } public OffsetIntMatrix translateTo(Position pos) { return new OffsetIntMatrix(pos.getRow(), pos.getCol(), value, defaultValue); } @Override public int getInt(int row, int col) { if (!isDefined(row, col)) { return defaultValue; } return value[row - rowOffset][col - colOffset]; } protected boolean isDefined(int row, int col) { return within(row, rowOffset, rows()) && within(col, colOffset, cols()); } protected int cols() { return value[0].length; } protected int rows() { return value.length; } public static OffsetIntMatrix concat(OffsetIntMatrix first, OffsetIntMatrix other, Integer defaultValue) { int lowerCol = Math.min(first.lowerCol(), other.lowerCol()); int lowerRow = Math.min(first.lowerRow(), other.lowerRow()); int upperColExclusive = Math.max(first.lowerCol() + first.cols(), other.lowerCol() + other.cols()); int upperRowExclusive = Math.max(first.lowerRow() + first.rows(), other.lowerRow() + other.rows()); OffsetIntMatrix matrix = new OffsetIntMatrix(lowerRow, lowerCol, upperRowExclusive - lowerRow, upperColExclusive - lowerCol, defaultValue); matrix.mutableTransform(IntFunctions.merge(first, (f, o) -> (o != other.defaultValue) ? o : f)); matrix.mutableTransform(IntFunctions.merge(other, (f, o) -> (o != other.defaultValue) ? o : f)); return matrix; } }