diff --git a/CHANGES.txt b/CHANGES.txt index 8865fb0f..4d25d40e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -7,11 +7,13 @@ 3*, Remove differenceOf from N, replaced with indexOfDifference -4, Add updateColumn/updateRow/updateAll/swapColumn/swapRow/moveRow to DataSet. +4, Add divideColumn/updateColumn/updateRow/updateAll/swapColumn/swapRow/moveColumn/moveRow to DataSet. 5, Add renameRow/renameColumn/updateRow/updateColumn/updateAll/copy(rowKeySet, columnKeySet)/addRow(rowIndex,...)/addColumn(columnIndex,...)/moveRow/moveColumn/swapRow/swapColumn/merge/freeze/frozen/clone to Sheet. -6, Improvements and bug fix. +6, Remove Sheet and rename ArraySheet to Sheet. + +7, Improvements and bug fix. ========Changes in 0.9.49========================================================================= diff --git a/lib/abacus-util-0.9.50.jar b/lib/abacus-util-0.9.50.jar deleted file mode 100644 index f77cea76..00000000 Binary files a/lib/abacus-util-0.9.50.jar and /dev/null differ diff --git a/lib/abacus-util-all-0.9.50.jar b/lib/abacus-util-all-0.9.50.jar index c520d5ee..03746b16 100644 Binary files a/lib/abacus-util-all-0.9.50.jar and b/lib/abacus-util-all-0.9.50.jar differ diff --git a/src/com/landawn/abacus/DataSet.java b/src/com/landawn/abacus/DataSet.java index e81e7b33..c0aa3de8 100644 --- a/src/com/landawn/abacus/DataSet.java +++ b/src/com/landawn/abacus/DataSet.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.Set; +import com.landawn.abacus.util.Sheet; import com.landawn.abacus.util.Multimap; import com.landawn.abacus.util.Multiset; import com.landawn.abacus.util.ObjectList; @@ -35,7 +36,6 @@ import com.landawn.abacus.util.OptionalDouble; import com.landawn.abacus.util.OptionalNullable; import com.landawn.abacus.util.Properties; -import com.landawn.abacus.util.Sheet; import com.landawn.abacus.util.function.BiFunction; import com.landawn.abacus.util.function.BiPredicate; import com.landawn.abacus.util.function.Consumer; @@ -575,6 +575,8 @@ public interface DataSet extends Iterable { void combineColumn(Predicate columnNameFilter, String newColumnName, Function combineFunc); + void divideColumn(String columnName, Collection newColumnNames, Function> divideFunc); + /** * * @param row can be Object[]/List/Map/Entity with getter/setter methods diff --git a/src/com/landawn/abacus/util/ArraySheet.java b/src/com/landawn/abacus/util/ArraySheet.java deleted file mode 100644 index 3962e8d0..00000000 --- a/src/com/landawn/abacus/util/ArraySheet.java +++ /dev/null @@ -1,1872 +0,0 @@ -/* - * Copyright (c) 2015, Haiyang Li. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.landawn.abacus.util; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Set; - -import com.landawn.abacus.DataSet; -import com.landawn.abacus.core.RowDataSet; -import com.landawn.abacus.parser.KryoParser; -import com.landawn.abacus.parser.ParserFactory; -import com.landawn.abacus.util.function.BiFunction; -import com.landawn.abacus.util.function.Function; -import com.landawn.abacus.util.stream.ImmutableIterator; -import com.landawn.abacus.util.stream.Stream; - -/** - * - * @since 0.8 - * - * @author Haiyang Li - */ -public final class ArraySheet implements Sheet { - private static final KryoParser kryoParser = ParserFactory.isKryoAvailable() ? ParserFactory.createKryoParser() : null; - - private final Set _rowKeySet; - private final Set _columnKeySet; - private BiMap _rowKeyIndexMap; - private BiMap _columnKeyIndexMap; - private List> _columnList; - private boolean _initialized = false; - private boolean _isFrozen = false; - - // For Kryo. - ArraySheet() { - this(N.EMPTY_LIST, N.EMPTY_LIST); - } - - public ArraySheet(Collection rowKeySet, Collection columnKeySet) { - this._rowKeySet = new LinkedHashSet<>(rowKeySet); - this._columnKeySet = new LinkedHashSet<>(columnKeySet); - } - - public ArraySheet(Collection rowKeySet, Collection columnKeySet, Object[][] rows) { - this(rowKeySet, columnKeySet); - - final int rowLength = this._rowKeySet.size(); - final int columnLength = this._columnKeySet.size(); - - if (N.notNullOrEmpty(rows)) { - N.checkArgument(rows.length == rowLength, "The length of array is not equal to size of row/column key set"); - - for (Object[] e : rows) { - N.checkArgument(e.length == columnLength, "The length of array is not equal to size of row/column key set"); - } - - initIndexMap(); - - _columnList = new ArrayList<>(columnLength); - - for (int i = 0; i < columnLength; i++) { - final List column = new ArrayList<>(rowLength); - - for (int j = 0; j < rowLength; j++) { - column.add((E) rows[j][i]); - } - - _columnList.add(column); - } - - _initialized = true; - } - } - - public static ArraySheet of(Collection rowKeySet, Collection columnKeySet, Object[][] rows) { - return new ArraySheet<>(rowKeySet, columnKeySet, rows); - } - - public static ArraySheet of(Collection rowKeySet, Collection columnKeySet, Collection> rows) { - final ArraySheet instance = new ArraySheet<>(rowKeySet, columnKeySet); - - final int rowLength = instance._rowKeySet.size(); - final int columnLength = instance._columnKeySet.size(); - - if (N.notNullOrEmpty(rows)) { - N.checkArgument(rows.size() == rowLength, "The size of collection is not equal to size of row/column key set"); - - for (Collection e : rows) { - N.checkArgument(e.size() == columnLength, "The size of collection is not equal to size of row/column key set"); - } - - instance.initIndexMap(); - - instance._columnList = new ArrayList<>(columnLength); - - for (int i = 0; i < columnLength; i++) { - instance._columnList.add(new ArrayList(rowLength)); - } - - for (Collection row : rows) { - final Iterator iter = row.iterator(); - - for (int i = 0; i < columnLength; i++) { - instance._columnList.get(i).add(iter.next()); - } - } - - instance._initialized = true; - } - - return instance; - - } - - public static ArraySheet from(Collection rowKeySet, Collection columnKeySet, Object[][] columns) { - final ArraySheet instance = new ArraySheet<>(rowKeySet, columnKeySet); - - final int rowLength = instance._rowKeySet.size(); - final int columnLength = instance._columnKeySet.size(); - - if (N.notNullOrEmpty(columns)) { - N.checkArgument(columns.length == columnLength, "The length of array is not equal to size of row/column key set"); - - for (Object[] e : columns) { - N.checkArgument(e.length == rowLength, "The length of array is not equal to size of row/column key set"); - } - - instance.initIndexMap(); - - instance._columnList = new ArrayList<>(columnLength); - - for (Object[] column : columns) { - instance._columnList.add(new ArrayList<>((List) Arrays.asList(column))); - } - - instance._initialized = true; - } - - return instance; - } - - public static ArraySheet from(Collection rowKeySet, Collection columnKeySet, - Collection> columns) { - final ArraySheet instance = new ArraySheet<>(rowKeySet, columnKeySet); - - final int rowLength = instance._rowKeySet.size(); - final int columnLength = instance._columnKeySet.size(); - - if (N.notNullOrEmpty(columns)) { - N.checkArgument(columns.size() == columnLength, "The size of collection is not equal to size of row/column key set"); - - for (Collection e : columns) { - N.checkArgument(e.size() == rowLength, "The size of collection is not equal to size of row/column key set"); - } - - instance.initIndexMap(); - - instance._columnList = new ArrayList<>(columnLength); - - for (Collection column : columns) { - instance._columnList.add(new ArrayList<>(column)); - } - - instance._initialized = true; - } - - return instance; - } - - @Override - public Set rowKeySet() { - return _rowKeySet; - } - - @Override - public Set columnKeySet() { - return _columnKeySet; - } - - @Override - public E get(Object rowKey, Object columnKey) { - if (_initialized) { - final int rowIndex = getRowIndex(rowKey); - final int columnIndex = getColumnIndex(columnKey); - - return get(rowIndex, columnIndex); - } else { - checkRowKey(rowKey); - checkColumnKey(columnKey); - - return null; - } - } - - /** - * - * @param rowIndex - * @param columnIndex - * @return - */ - public E get(int rowIndex, int columnIndex) { - if (_initialized) { - return _columnList.get(columnIndex).get(rowIndex); - } else { - checkRowIndex(rowIndex); - checkColumnIndex(columnIndex); - - return null; - } - } - - @Override - public E put(R rowKey, C columnKey, E value) { - checkFrozen(); - - init(); - - final int rowIndex = getRowIndex(rowKey); - final int columnIndex = getColumnIndex(columnKey); - - return put(rowIndex, columnIndex, value); - } - - public E put(int rowIndex, int columnIndex, E value) { - checkFrozen(); - - init(); - - final Object previousValue = _columnList.get(columnIndex).get(rowIndex); - _columnList.get(columnIndex).set(rowIndex, value); - - return (E) previousValue; - } - - @Override - public void putAll(Sheet source) { - checkFrozen(); - - if (!this.rowKeySet().containsAll(source.rowKeySet())) { - throw new IllegalArgumentException(source.rowKeySet() + " are not all included in this sheet with row key set: " + this.rowKeySet()); - } - - if (!this.columnKeySet().containsAll(source.columnKeySet())) { - throw new IllegalArgumentException(source.columnKeySet() + " are not all included in this sheet with column key set: " + this.columnKeySet()); - } - - final Sheet tmp = (Sheet) source; - for (R r : tmp.rowKeySet()) { - for (C c : tmp.columnKeySet()) { - this.put(r, c, tmp.get(r, c)); - } - } - } - - @Override - public E remove(Object rowKey, Object columnKey) { - checkFrozen(); - - if (_initialized) { - final int rowIndex = getRowIndex(rowKey); - final int columnIndex = getColumnIndex(columnKey); - - return remove(rowIndex, columnIndex); - } else { - checkRowKey(rowKey); - checkColumnKey(columnKey); - - return null; - } - } - - public E remove(int rowIndex, int columnIndex) { - checkFrozen(); - - if (_initialized) { - return _columnList.get(columnIndex).set(rowIndex, null); - } else { - checkRowIndex(rowIndex); - checkColumnIndex(columnIndex); - - return null; - } - } - - @Override - public boolean contains(Object rowKey, Object columnKey) { - return get(rowKey, columnKey) != null; - } - - @Override - public boolean containsValue(Object value) { - // if (value == null) { - // for (R r : rowKeySet()) { - // for (C c : columnKeySet()) { - // if (this.get(r, c) == null) { - // return true; - // } - // } - // } - // } else { - // for (R r : rowKeySet()) { - // for (C c : columnKeySet()) { - // if (value.equals(this.get(r, c))) { - // return true; - // } - // } - // } - // } - // - // return false; - - if (this._initialized) { - for (List column : _columnList) { - if (column.contains(value)) { - return true; - } - } - - return false; - } else { - return value == null; - } - } - - @Override - public List getRow(Object rowKey) { - final int columnLength = columnLength(); - final List row = new ArrayList<>(columnLength); - - if (_initialized) { - final int rowIndex = getRowIndex(rowKey); - - for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { - row.add(_columnList.get(columnIndex).get(rowIndex)); - } - } else { - checkRowKey(rowKey); - - N.fill(row, 0, columnLength, null); - } - - return N.asImmutableList(row); - } - - @Override - public void setRow(R rowKey, Collection row) { - final int columnLength = columnLength(); - - if (N.notNullOrEmpty(row) && row.size() != columnLength) { - throw new IllegalArgumentException("The size of specified row: " + row.size() + " doesn't match the length of column key set: " + columnLength); - } - - init(); - - final int rowIndex = getRowIndex(rowKey); - - if (N.isNullOrEmpty(row)) { - for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { - _columnList.get(columnIndex).set(rowIndex, null); - } - } else { - final Iterator iter = row.iterator(); - - for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { - _columnList.get(columnIndex).set(rowIndex, iter.next()); - } - } - } - - @Override - public void addRow(R rowKey, Collection row) { - checkFrozen(); - - if (_rowKeySet.contains(rowKey)) { - throw new IllegalArgumentException("Row '" + rowKey + "' already existed"); - } - - final int rowLength = rowLength(); - final int columnLength = columnLength(); - - if (N.notNullOrEmpty(row) && row.size() != columnLength) { - throw new IllegalArgumentException("The size of specified row: " + row.size() + " doesn't match the length of column key set: " + columnLength); - } - - init(); - - _rowKeySet.add(rowKey); - _rowKeyIndexMap.put(rowKey, rowLength); - - if (N.isNullOrEmpty(row)) { - for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { - _columnList.get(columnIndex).add(null); - } - } else { - final Iterator iter = row.iterator(); - - for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { - _columnList.get(columnIndex).add(iter.next()); - } - } - } - - @Override - public void addRow(final int rowIndex, final R rowKey, final Collection row) { - checkFrozen(); - - final int rowLength = rowLength(); - final int columnLength = columnLength(); - - if (rowIndex == rowLength) { - addRow(rowKey, row); - return; - } - - if (rowIndex < 0 || rowIndex > rowLength) { - throw new IllegalArgumentException("Invalid row index: " + rowIndex + ". It must be: >= 0 and <= " + rowLength); - } - - if (_rowKeySet.contains(rowKey)) { - throw new IllegalArgumentException("Row '" + rowKey + "' already existed"); - } - - if (N.notNullOrEmpty(row) && row.size() != columnLength) { - throw new IllegalArgumentException("The size of specified row: " + row.size() + " doesn't match the length of column key set: " + columnLength); - } - - init(); - - final List tmp = new ArrayList<>(rowLength + 1); - tmp.addAll(_rowKeySet); - tmp.add(rowIndex, rowKey); - - _rowKeySet.clear(); - _rowKeySet.addAll(tmp); - - for (Map.Entry entry : _rowKeyIndexMap.entrySet()) { - if (entry.getValue().intValue() >= rowIndex) { - entry.setValue(entry.getValue() + 1); - } - } - - _rowKeyIndexMap.put(rowKey, rowIndex); - - if (N.isNullOrEmpty(row)) { - for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { - _columnList.get(columnIndex).add(rowIndex, null); - } - } else { - final Iterator iter = row.iterator(); - - for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { - _columnList.get(columnIndex).add(rowIndex, iter.next()); - } - } - - } - - @Override - public void updateRow(R rowKey, Function func) { - checkFrozen(); - - if (columnLength() > 0) { - this.init(); - - final int rowIndex = this.getRowIndex(rowKey); - - for (List column : _columnList) { - column.set(rowIndex, func.apply(column.get(rowIndex))); - } - } - } - - @Override - public void removeRow(Object rowKey) { - checkFrozen(); - - checkRowKey(rowKey); - - _rowKeySet.remove(rowKey); - - if (_rowKeyIndexMap != null) { - final int columnLength = columnLength(); - final int newRowSize = _rowKeySet.size(); - final int removedRowIndex = _rowKeyIndexMap.remove(rowKey); - - if (removedRowIndex == newRowSize) { - // removed last row. - } else { - for (int i = removedRowIndex; i < newRowSize; i++) { - _rowKeyIndexMap.put(_rowKeyIndexMap.getByValue(i + 1), i); - } - } - - if (_initialized) { - for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { - _columnList.get(columnIndex).remove(removedRowIndex); - } - } - } - } - - @Override - public void moveRow(Object rowKey, int newRowIndex) { - checkFrozen(); - - this.checkRowIndex(newRowIndex); - - final int rowIndex = this.getRowIndex(rowKey); - final List tmp = new ArrayList<>(rowLength()); - tmp.addAll(_rowKeySet); - tmp.add(newRowIndex, tmp.remove(rowIndex)); - - _rowKeySet.clear(); - _rowKeySet.addAll(tmp); - - _rowKeyIndexMap = null; - - if (_initialized && _columnList.size() > 0) { - for (List column : _columnList) { - column.add(newRowIndex, column.remove(rowIndex)); - } - } - } - - @Override - public void swapRow(Object rowKeyA, Object rowKeyB) { - checkFrozen(); - - final int rowIndexA = this.getRowIndex(rowKeyA); - final int rowIndexB = this.getRowIndex(rowKeyB); - - final List tmp = new ArrayList<>(rowLength()); - tmp.addAll(_rowKeySet); - final R tmpRowKeyA = tmp.get(rowIndexA); - tmp.set(rowIndexA, tmp.get(rowIndexB)); - tmp.set(rowIndexB, tmpRowKeyA); - - _rowKeySet.clear(); - _rowKeySet.addAll(tmp); - - _rowKeyIndexMap.put(tmp.get(rowIndexA), rowIndexA); - _rowKeyIndexMap.put(tmp.get(rowIndexB), rowIndexB); - - if (_initialized && _columnList.size() > 0) { - E tmpVal = null; - - for (List column : _columnList) { - tmpVal = column.get(rowIndexA); - column.set(rowIndexA, column.get(rowIndexB)); - column.set(rowIndexB, tmpVal); - } - } - } - - @Override - public void renameRow(R rowKey, R newRowKey) { - checkFrozen(); - checkRowKey(rowKey); - - if (this._rowKeySet.contains(newRowKey)) { - throw new IllegalArgumentException("Invalid new row key: " + N.toString(newRowKey) + ". It's already in the row key set."); - } - - final int rowIndex = this.getRowIndex(rowKey); - final List tmp = new ArrayList<>(_rowKeySet); - tmp.set(rowIndex, newRowKey); - - this._rowKeySet.clear(); - this._rowKeySet.addAll(tmp); - - if (N.notNullOrEmpty(this._rowKeyIndexMap)) { - this._rowKeyIndexMap.put(newRowKey, _rowKeyIndexMap.remove(rowKey)); - } - } - - @Override - public boolean containsRow(Object rowKey) { - return _rowKeySet.contains(rowKey); - } - - @Override - public Map row(Object rowKey) { - final int columnLength = columnLength(); - Map rowMap = new LinkedHashMap<>(N.initHashCapacity(columnLength)); - - if (_initialized) { - final int rowIndex = getRowIndex(rowKey); - int columnIndex = 0; - - for (C columnKey : this.columnKeySet()) { - rowMap.put(columnKey, _columnList.get(columnIndex++).get(rowIndex)); - } - } else { - checkRowKey(rowKey); - - for (C columnKey : this.columnKeySet()) { - rowMap.put(columnKey, null); - } - } - - return rowMap; - } - - @Override - public Map> rowMap() { - final Map> result = new LinkedHashMap<>(N.initHashCapacity(this.rowKeySet().size())); - - for (R rowKey : this.rowKeySet()) { - result.put(rowKey, row(rowKey)); - } - - return result; - } - - @Override - public List getColumn(Object columnKey) { - final int rowLength = rowLength(); - List column = null; - - if (_initialized) { - column = _columnList.get(getColumnIndex(columnKey)); - } else { - checkColumnKey(columnKey); - column = new ArrayList<>(rowLength); - N.fill(column, 0, rowLength, null); - } - - return N.asImmutableList(column); - } - - @Override - public void setColumn(C columnKey, Collection column) { - checkFrozen(); - - final int rowLength = rowLength(); - - if (N.notNullOrEmpty(column) && column.size() != rowLength) { - throw new IllegalArgumentException("The size of specified column: " + column.size() + " doesn't match the length of row key set: " + rowLength); - } - - init(); - - final int columnIndex = getColumnIndex(columnKey); - - if (N.isNullOrEmpty(column)) { - N.fill(_columnList.get(columnIndex), 0, rowLength, null); - } else { - _columnList.set(columnIndex, new ArrayList<>(column)); - } - } - - @Override - public void addColumn(C columnKey, Collection column) { - checkFrozen(); - - if (_columnKeySet.contains(columnKey)) { - throw new IllegalArgumentException("Column '" + columnKey + "' already existed"); - } - - final int rowLength = rowLength(); - final int columnLength = columnLength(); - - if (N.notNullOrEmpty(column) && column.size() != rowLength) { - throw new IllegalArgumentException("The size of specified column: " + column.size() + " doesn't match the length of row key set: " + rowLength); - } - - init(); - - _columnKeySet.add(columnKey); - _columnKeyIndexMap.put(columnKey, columnLength); - - if (N.isNullOrEmpty(column)) { - List newColumn = new ArrayList<>(); - N.fill(newColumn, 0, rowLength, null); - _columnList.add(newColumn); - } else { - _columnList.add(new ArrayList<>(column)); - } - } - - @Override - public void addColumn(int columnIndex, C columnKey, Collection column) { - checkFrozen(); - - final int rowLength = rowLength(); - final int columnLength = columnLength(); - - if (columnIndex == columnLength) { - addColumn(columnKey, column); - return; - } - - if (columnIndex < 0 || columnIndex > columnLength) { - throw new IllegalArgumentException("Invalid column index: " + columnIndex + ". It must be: >= 0 and <= " + columnLength); - } - - if (_columnKeySet.contains(columnKey)) { - throw new IllegalArgumentException("Column '" + columnKey + "' already existed"); - } - - if (N.notNullOrEmpty(column) && column.size() != rowLength) { - throw new IllegalArgumentException("The size of specified column: " + column.size() + " doesn't match the length of row key set: " + rowLength); - } - - init(); - - final List tmp = new ArrayList<>(columnLength + 1); - tmp.addAll(_columnKeySet); - tmp.add(columnIndex, columnKey); - - _columnKeySet.clear(); - _columnKeySet.addAll(tmp); - - for (Map.Entry entry : _columnKeyIndexMap.entrySet()) { - if (entry.getValue().intValue() >= columnIndex) { - entry.setValue(entry.getValue() + 1); - } - } - - _columnKeyIndexMap.put(columnKey, columnIndex); - - if (N.isNullOrEmpty(column)) { - List newColumn = new ArrayList<>(); - N.fill(newColumn, 0, rowLength, null); - _columnList.add(columnIndex, newColumn); - } else { - _columnList.add(columnIndex, new ArrayList<>(column)); - } - } - - @Override - public void updateColumn(C columnKey, Function func) { - checkFrozen(); - - if (rowLength() > 0) { - this.init(); - - final int rowLength = rowLength(); - final List column = _columnList.get(this.getColumnIndex(columnKey)); - - for (int rowIndex = 0; rowIndex < rowLength; rowIndex++) { - column.set(rowIndex, func.apply(column.get(rowIndex))); - } - } - } - - @Override - public void removeColumn(Object columnKey) { - checkFrozen(); - - checkColumnKey(columnKey); - - _columnKeySet.remove(columnKey); - - if (_columnKeyIndexMap != null) { - final int newColumnLength = _columnKeySet.size(); - final int removedColumnIndex = _columnKeyIndexMap.remove(columnKey); - - if (removedColumnIndex == newColumnLength) { - // removed the last column - } else { - for (int i = removedColumnIndex; i < newColumnLength; i++) { - _columnKeyIndexMap.put(_columnKeyIndexMap.getByValue(i + 1), i); - } - } - - if (_initialized) { - _columnList.remove(removedColumnIndex); - } - } - } - - @Override - public void moveColumn(Object columnKey, int newColumnIndex) { - checkFrozen(); - - this.checkColumnIndex(newColumnIndex); - - final int columnIndex = this.getColumnIndex(columnKey); - final List tmp = new ArrayList<>(columnLength()); - tmp.addAll(_columnKeySet); - tmp.add(newColumnIndex, tmp.remove(columnIndex)); - - _columnKeySet.clear(); - _columnKeySet.addAll(tmp); - - _columnKeyIndexMap = null; - - if (_initialized && _columnList.size() > 0) { - _columnList.add(newColumnIndex, _columnList.remove(columnIndex)); - } - } - - @Override - public void swapColumn(Object columnKeyA, Object columnKeyB) { - checkFrozen(); - - final int columnIndexA = this.getColumnIndex(columnKeyA); - final int columnIndexB = this.getColumnIndex(columnKeyB); - - final List tmp = new ArrayList<>(rowLength()); - tmp.addAll(_columnKeySet); - final C tmpColumnKeyA = tmp.get(columnIndexA); - tmp.set(columnIndexA, tmp.get(columnIndexB)); - tmp.set(columnIndexB, tmpColumnKeyA); - - _columnKeySet.clear(); - _columnKeySet.addAll(tmp); - - _columnKeyIndexMap.put(tmp.get(columnIndexA), columnIndexA); - _columnKeyIndexMap.put(tmp.get(columnIndexB), columnIndexB); - - if (_initialized && _columnList.size() > 0) { - final List tmpColumnA = _columnList.get(columnIndexA); - - _columnList.set(columnIndexA, _columnList.get(columnIndexB)); - _columnList.set(columnIndexB, tmpColumnA); - } - } - - @Override - public void renameColumn(C columnKey, C newColumnKey) { - checkFrozen(); - - this.checkColumnKey(columnKey); - - if (this._columnKeySet.contains(newColumnKey)) { - throw new IllegalArgumentException("Invalid new column key: " + N.toString(newColumnKey) + ". It's already in the column key set."); - } - - final int columnIndex = this.getColumnIndex(columnKey); - final List tmp = new ArrayList<>(_columnKeySet); - tmp.set(columnIndex, newColumnKey); - - this._columnKeySet.clear(); - this._columnKeySet.addAll(tmp); - - if (N.notNullOrEmpty(this._columnKeyIndexMap)) { - this._columnKeyIndexMap.put(newColumnKey, _columnKeyIndexMap.remove(columnKey)); - } - } - - @Override - public boolean containsColumn(Object columnKey) { - return _columnKeySet.contains(columnKey); - } - - @Override - public Map column(Object columnKey) { - final int rowLength = rowLength(); - final Map columnMap = new LinkedHashMap<>(N.initHashCapacity(rowLength)); - - if (_initialized) { - final int columnIndex = getColumnIndex(columnKey); - final List column = _columnList.get(columnIndex); - int rowIndex = 0; - - for (R rowKey : this.rowKeySet()) { - columnMap.put(rowKey, column.get(rowIndex++)); - } - } else { - checkColumnKey(columnKey); - - for (R rowKey : this.rowKeySet()) { - columnMap.put(rowKey, null); - } - } - - return columnMap; - } - - @Override - public Map> columnMap() { - final Map> result = new LinkedHashMap<>(N.initHashCapacity(this.columnKeySet().size())); - - for (C columnKey : this.columnKeySet()) { - result.put(columnKey, column(columnKey)); - } - - return result; - } - - @Override - public int rowLength() { - return _rowKeySet.size(); - } - - @Override - public int columnLength() { - return _columnKeySet.size(); - } - - @Override - public void updateAll(Function func) { - checkFrozen(); - - if (rowLength() > 0 && columnLength() > 0) { - this.init(); - - final int rowLength = rowLength(); - - for (List column : _columnList) { - for (int rowIndex = 0; rowIndex < rowLength; rowIndex++) { - column.set(rowIndex, func.apply(column.get(rowIndex))); - } - } - } - } - - @Override - public ArraySheet copy() { - final ArraySheet copy = new ArraySheet<>(this._rowKeySet, this._columnKeySet); - - if (this._initialized) { - copy.initIndexMap(); - - copy._columnList = new ArrayList<>(_columnList.size()); - - for (List column : _columnList) { - copy._columnList.add(new ArrayList<>(column)); - } - - copy._initialized = true; - } - - return copy; - } - - @Override - public ArraySheet copy(Collection rowKeySet, Collection columnKeySet) { - if (this._rowKeySet.containsAll(rowKeySet) == false) { - throw new IllegalArgumentException( - "Row keys: " + N.difference(rowKeySet, this._rowKeySet) + " are not included in this sheet row keys: " + this._rowKeySet); - } - - if (this._columnKeySet.containsAll(columnKeySet) == false) { - throw new IllegalArgumentException( - "Column keys: " + N.difference(columnKeySet, this._columnKeySet) + " are not included in this sheet Column keys: " + this._columnKeySet); - } - - final ArraySheet copy = new ArraySheet<>(rowKeySet, columnKeySet); - - if (this._initialized) { - copy.initIndexMap(); - - copy._columnList = new ArrayList<>(copy._columnKeySet.size()); - - final int[] rowKeyIndices = new int[copy._rowKeySet.size()]; - int idx = 0; - - for (R rowKey : copy._rowKeySet) { - rowKeyIndices[idx++] = this.getRowIndex(rowKey); - } - - for (C columnKey : copy._columnKeySet) { - final List column = _columnList.get(this.getColumnIndex(columnKey)); - final List newColumn = new ArrayList<>(rowKeyIndices.length); - - for (int rowIndex : rowKeyIndices) { - newColumn.add(column.get(rowIndex)); - } - - copy._columnList.add(newColumn); - } - - copy._initialized = true; - } - - return copy; - } - - @Override - public Sheet clone() { - return clone(this._isFrozen); - } - - @Override - public Sheet clone(boolean freeze) { - if (kryoParser == null) { - throw new RuntimeException("Kryo is required"); - } - - final ArraySheet copy = kryoParser.clone(this); - - copy._isFrozen = freeze; - - return copy; - } - - @Override - public Sheet merge(Sheet source, BiFunction mergeFunction) { - final ArraySheet result = this.copy(); - - for (R rowKey : source.rowKeySet()) { - if (result.containsRow(rowKey) == false) { - result.addRow(rowKey, null); - } - } - - for (C columnKey : source.columnKeySet()) { - if (result.containsColumn(columnKey) == false) { - result.addColumn(columnKey, null); - } - } - - final int[] rowKeyIndexes = new int[source.rowLength()]; - final int[] columnKeyIndexes = new int[source.columnLength()]; - - int idx = 0; - for (R rowKey : source.rowKeySet()) { - rowKeyIndexes[idx++] = result.getRowIndex(rowKey); - } - - idx = 0; - for (C columnKey : source.columnKeySet()) { - columnKeyIndexes[idx++] = result.getColumnIndex(columnKey); - } - - final Iterator iter = source.columnKeySet().iterator(); - - for (int columnIndex = 0, columnLength = columnKeyIndexes.length; columnIndex < columnLength; columnIndex++) { - final List srcColumn = source.getColumn(iter.next()); - final List targetColumn = _columnList.get(columnKeyIndexes[columnIndex]); - - for (int rowIndex = 0, rowLength = rowKeyIndexes.length; rowIndex < rowLength; rowIndex++) { - targetColumn.set(rowKeyIndexes[rowIndex], mergeFunction.apply(targetColumn.get(rowKeyIndexes[rowIndex]), srcColumn.get(rowIndex))); - } - } - - return result; - } - - @Override - public Sheet transpose() { - final ArraySheet copy = new ArraySheet<>(this._columnKeySet, this._rowKeySet); - - if (this._initialized) { - copy.initIndexMap(); - - final int rowLength = copy.rowLength(); - final int columnLength = copy.columnLength(); - - copy._columnList = new ArrayList<>(columnLength); - - for (int i = 0; i < columnLength; i++) { - final List column = new ArrayList<>(rowLength); - - for (int j = 0; j < rowLength; j++) { - column.add(_columnList.get(j).get(i)); - } - - copy._columnList.add(column); - } - - copy._initialized = true; - } - - return copy; - } - - @Override - public void freeze() { - _isFrozen = true; - } - - @Override - public boolean frozen() { - return _isFrozen; - } - - @Override - public void clear() { - checkFrozen(); - - if (_initialized && _columnList.size() > 0) { - for (List column : _columnList) { - N.fill(column, 0, column.size(), null); - } - } - } - - @Override - public void trimToSize() { - if (_initialized && _columnList.size() > 0) { - for (List column : _columnList) { - if (column instanceof ArrayList) { - ((ArrayList) column).trimToSize(); - } - } - } - } - - @Override - public Stream> cells() { - return cells(0, _rowKeySet.size()); - } - - @Override - public Stream> cells(final int fromRowIndex, final int toRowIndex) { - N.checkIndex(fromRowIndex, toRowIndex, _rowKeySet.size()); - - if (_rowKeySet.size() == 0 || _columnKeySet.size() == 0) { - return Stream.empty(); - } - - initIndexMap(); - - return Stream.of(new ImmutableIterator>() { - private final int columnLength = columnLength(); - private final long toIndex = toRowIndex * columnLength * 1L; - private long cursor = fromRowIndex * columnLength * 1L; - - @Override - public boolean hasNext() { - return cursor < toIndex; - } - - @Override - public Sheet.Cell next() { - if (cursor >= toIndex) { - throw new NoSuchElementException(); - } - - final int rowIndex = (int) (cursor / columnLength); - final int columnIndex = (int) (cursor++ % columnLength); - - return new Cell0<>(_rowKeyIndexMap.getByValue(rowIndex), _columnKeyIndexMap.getByValue(columnIndex), - _initialized ? _columnList.get(columnIndex).get(rowIndex) : null); - } - - @Override - public void skip(long n) { - cursor = n < toIndex - cursor ? cursor + n : toIndex; - } - - @Override - public long count() { - return toIndex - cursor; - } - }); - } - - @Override - public Stream> cells0() { - return cells0(0, _columnKeySet.size()); - } - - @Override - public Stream> cells0(final int fromColumnIndex, final int toColumnIndex) { - N.checkIndex(fromColumnIndex, toColumnIndex, _columnKeySet.size()); - - if (_rowKeySet.size() == 0 || _columnKeySet.size() == 0) { - return Stream.empty(); - } - - initIndexMap(); - - return Stream.of(new ImmutableIterator>() { - private final int rowLength = rowLength(); - private final long toIndex = toColumnIndex * rowLength * 1L; - private long cursor = fromColumnIndex * rowLength * 1L; - - @Override - public boolean hasNext() { - return cursor < toIndex; - } - - @Override - public Sheet.Cell next() { - if (cursor >= toIndex) { - throw new NoSuchElementException(); - } - - final int rowIndex = (int) (cursor % rowLength); - final int columnIndex = (int) (cursor++ / rowLength); - - return new Cell0<>(_rowKeyIndexMap.getByValue(rowIndex), _columnKeyIndexMap.getByValue(columnIndex), - _initialized ? _columnList.get(columnIndex).get(rowIndex) : null); - } - - @Override - public void skip(long n) { - cursor = n < toIndex - cursor ? cursor + n : toIndex; - } - - @Override - public long count() { - return toIndex - cursor; - } - }); - } - - @Override - public Stream stream() { - return stream(0, _rowKeySet.size()); - } - - @Override - public Stream stream(final int fromRowIndex, final int toRowIndex) { - N.checkIndex(fromRowIndex, toRowIndex, _rowKeySet.size()); - - if (_rowKeySet.size() == 0 || _columnKeySet.size() == 0) { - return Stream.empty(); - } - - return Stream.of(new ImmutableIterator() { - private final int columnLength = columnLength(); - private final long toIndex = toRowIndex * columnLength * 1L; - private long cursor = fromRowIndex * columnLength * 1L; - - @Override - public boolean hasNext() { - return cursor < toIndex; - } - - @Override - public E next() { - if (cursor >= toIndex) { - throw new NoSuchElementException(); - } - - if (_initialized) { - return _columnList.get((int) (cursor % columnLength)).get((int) (cursor++ / columnLength)); - } else { - cursor++; - return null; - } - } - - @Override - public void skip(long n) { - cursor = n < toIndex - cursor ? cursor + n : toIndex; - } - - @Override - public long count() { - return toIndex - cursor; - } - }); - } - - @Override - public Stream stream0() { - return stream0(0, _columnKeySet.size()); - } - - @Override - public Stream stream0(final int fromColumnIndex, final int toColumnIndex) { - N.checkIndex(fromColumnIndex, toColumnIndex, _columnKeySet.size()); - - if (_rowKeySet.size() == 0 || _columnKeySet.size() == 0) { - return Stream.empty(); - } - - return Stream.of(new ImmutableIterator() { - private final int rowLength = rowLength(); - private final long toIndex = toColumnIndex * rowLength * 1L; - private long cursor = fromColumnIndex * rowLength * 1L; - - @Override - public boolean hasNext() { - return cursor < toIndex; - } - - @Override - public E next() { - if (cursor >= toIndex) { - throw new NoSuchElementException(); - } - - if (_initialized) { - return _columnList.get((int) (cursor / rowLength)).get((int) (cursor++ % rowLength)); - } else { - cursor++; - return null; - } - } - - @Override - public void skip(long n) { - cursor = n < toIndex - cursor ? cursor + n : toIndex; - } - - @Override - public long count() { - return toIndex - cursor; - } - }); - } - - @Override - public Stream> stream2() { - return stream2(0, _rowKeySet.size()); - } - - @Override - public Stream> stream2(final int fromRowIndex, final int toRowIndex) { - N.checkIndex(fromRowIndex, toRowIndex, _rowKeySet.size()); - - if (_rowKeySet.size() == 0 || _columnKeySet.size() == 0) { - return Stream.empty(); - } - - return Stream.of(new ImmutableIterator>() { - private final int toIndex = toRowIndex; - private volatile int cursor = fromRowIndex; - - @Override - public boolean hasNext() { - return cursor < toIndex; - } - - @Override - public Stream next() { - if (cursor >= toIndex) { - throw new NoSuchElementException(); - } - - return Stream.of(new ImmutableIterator() { - private final int rowIndex = cursor++; - private final int toIndex2 = _columnKeySet.size(); - private int cursor2 = 0; - - @Override - public boolean hasNext() { - return cursor2 < toIndex2; - } - - @Override - public E next() { - if (cursor2 >= toIndex2) { - throw new NoSuchElementException(); - } - - if (_initialized) { - return _columnList.get(cursor2++).get(rowIndex); - } else { - cursor2++; - return null; - } - } - - @Override - public void skip(long n) { - cursor2 = n < toIndex2 - cursor2 ? cursor2 + (int) n : toIndex2; - } - - @Override - public long count() { - return toIndex2 - cursor2; - } - }); - } - - @Override - public void skip(long n) { - cursor = n < toIndex - cursor ? cursor + (int) n : toIndex; - } - - @Override - public long count() { - return toIndex - cursor; - } - }); - } - - @Override - public Stream> stream02() { - return stream02(0, _columnKeySet.size()); - } - - @Override - public Stream> stream02(final int fromColumnIndex, final int toColumnIndex) { - N.checkIndex(fromColumnIndex, toColumnIndex, _columnKeySet.size()); - - if (_rowKeySet.size() == 0 || _columnKeySet.size() == 0) { - return Stream.empty(); - } - - return Stream.of(new ImmutableIterator>() { - private final int toIndex = toColumnIndex; - private int cursor = fromColumnIndex; - - @Override - public boolean hasNext() { - return cursor < toIndex; - } - - @Override - public Stream next() { - if (cursor >= toIndex) { - throw new NoSuchElementException(); - } - - if (_initialized) { - return Stream.of(_columnList.get(cursor++)); - } else { - cursor++; - return Stream.repeat(null, rowLength()); - } - } - - @Override - public void skip(long n) { - cursor = n < toIndex - cursor ? cursor + (int) n : toIndex; - } - - @Override - public long count() { - return toIndex - cursor; - } - }); - } - - @Override - public DataSet toDataSet() { - final int rowLength = rowLength(); - final int columnLength = columnLength(); - final List dataSetColumnNameList = new ArrayList<>(columnLength); - - for (C columnKey : _columnKeySet) { - dataSetColumnNameList.add(N.toString(columnKey)); - } - - final List> dataSetColumnList = new ArrayList<>(columnLength); - - if (_initialized) { - for (List column : _columnList) { - dataSetColumnList.add(new ArrayList(column)); - } - } else { - for (int i = 0; i < columnLength; i++) { - List column = new ArrayList<>(rowLength); - N.fill(column, 0, rowLength, null); - dataSetColumnList.add(column); - } - } - - return new RowDataSet(dataSetColumnNameList, dataSetColumnList); - } - - @Override - public DataSet toDataSet0() { - final int rowLength = rowLength(); - final int columnLength = columnLength(); - final List dataSetColumnNameList = new ArrayList<>(rowLength); - - for (R rowKey : _rowKeySet) { - dataSetColumnNameList.add(N.toString(rowKey)); - } - - final List> dataSetColumnList = new ArrayList<>(rowLength); - - if (_initialized) { - for (int i = 0; i < rowLength; i++) { - final List column = new ArrayList<>(columnLength); - - for (int j = 0; j < columnLength; j++) { - column.add(_columnList.get(j).get(i)); - } - - dataSetColumnList.add(column); - } - } else { - for (int i = 0; i < rowLength; i++) { - List column = new ArrayList<>(columnLength); - N.fill(column, 0, columnLength, null); - dataSetColumnList.add(column); - } - } - - return new RowDataSet(dataSetColumnNameList, dataSetColumnList); - } - - @Override - public Matrix toMatrix(Class cls) { - final int rowLength = rowLength(); - final int columnLength = columnLength(); - final E[][] c = N.newArray(N.newArray(cls, 0).getClass(), rowLength); - - for (int i = 0; i < rowLength; i++) { - c[i] = N.newArray(cls, columnLength); - } - - if (rowLength == 0 || columnLength == 0 || _initialized == false) { - return new Matrix<>(c); - } - - for (int i = 0; i < columnLength; i++) { - final List column = _columnList.get(i); - - for (int j = 0; j < rowLength; j++) { - c[j][i] = column.get(j); - } - } - - return new Matrix<>(c); - } - - @Override - public Matrix toMatrix0(Class cls) { - final int rowLength = rowLength(); - final int columnLength = columnLength(); - final E[][] c = N.newArray(N.newArray(cls, 0).getClass(), columnLength); - - for (int i = 0; i < columnLength; i++) { - c[i] = N.newArray(cls, rowLength); - } - - if (rowLength == 0 || columnLength == 0 || _initialized == false) { - return new Matrix<>(c); - } - - for (int i = 0; i < columnLength; i++) { - final List column = _columnList.get(i); - - for (int j = 0; j < rowLength; j++) { - c[i][j] = column.get(j); - } - } - - return new Matrix<>(c); - } - - @Override - public Object[][] toArray() { - final int rowLength = rowLength(); - final int columnLength = columnLength(); - final Object[][] copy = new Object[rowLength][columnLength]; - - if (_initialized) { - for (int i = 0; i < columnLength; i++) { - final List column = _columnList.get(i); - - for (int j = 0; j < rowLength; j++) { - copy[j][i] = column.get(j); - } - } - } - - return copy; - } - - @Override - public T[][] toArray(Class cls) { - final int rowLength = rowLength(); - final int columnLength = columnLength(); - final T[][] copy = N.newArray(N.newArray(cls, 0).getClass(), rowLength); - - for (int i = 0; i < rowLength; i++) { - copy[i] = N.newArray(cls, columnLength); - } - - if (_initialized) { - for (int i = 0; i < columnLength; i++) { - final List column = _columnList.get(i); - - for (int j = 0; j < rowLength; j++) { - copy[j][i] = (T) column.get(j); - } - } - } - - return copy; - } - - @Override - public Object[][] toArray0() { - final int rowLength = rowLength(); - final int columnLength = columnLength(); - final Object[][] copy = new Object[columnLength][rowLength]; - - if (_initialized) { - for (int i = 0; i < columnLength; i++) { - final List column = _columnList.get(i); - - for (int j = 0; j < rowLength; j++) { - copy[i][j] = column.get(j); - } - } - } - - return copy; - } - - @Override - public T[][] toArray0(Class cls) { - final int rowLength = rowLength(); - final int columnLength = columnLength(); - final T[][] copy = N.newArray(N.newArray(cls, 0).getClass(), columnLength); - - for (int i = 0; i < columnLength; i++) { - copy[i] = N.newArray(cls, rowLength); - } - - if (_initialized) { - for (int i = 0; i < columnLength; i++) { - final List column = _columnList.get(i); - - for (int j = 0; j < rowLength; j++) { - copy[i][j] = (T) column.get(j); - } - } - } - - return copy; - } - - @Override - public void println() { - final int columnLength = columnLength(); - N.println(Joiner.with(", ", " ", "").join(_columnKeySet).toString()); - - int i = 0; - for (R rowKey : _rowKeySet) { - final Joiner joiner = Joiner.with(", "); - joiner.add(rowKey); - - if (this._initialized) { - for (int j = 0; j < columnLength; j++) { - joiner.add(_columnList.get(j).get(i)); - } - } else { - for (int j = 0; j < columnLength; j++) { - joiner.add(N.NULL_STRING); - } - } - - i++; - - N.println(joiner.toString()); - } - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((_rowKeySet == null) ? 0 : _rowKeySet.hashCode()); - result = prime * result + ((_columnKeySet == null) ? 0 : _columnKeySet.hashCode()); - result = prime * result + (_initialized ? _columnList.hashCode() : 0); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (obj instanceof ArraySheet) { - ArraySheet other = (ArraySheet) obj; - - return N.equals(other._rowKeySet, _rowKeySet) && N.equals(other._columnKeySet, _columnKeySet) && N.deepEquals(other._columnList, _columnList); - } - - return false; - } - - @Override - public String toString() { - final StringBuilder sb = ObjectFactory.createStringBuilder(); - - sb.append("{rowKeySet="); - sb.append(_rowKeySet); - sb.append(", columnKeySet="); - sb.append(_columnKeySet); - sb.append(", rowList="); - sb.append("["); - - if (_initialized) { - for (int i = 0, rowLength = _rowKeySet.size(), columnLength = _columnKeySet.size(); i < rowLength; i++) { - if (i > 0) { - sb.append(N.ELEMENT_SEPARATOR_CHAR_ARRAY); - } - - sb.append("["); - - for (int j = 0; j < columnLength; j++) { - if (j > 0) { - sb.append(N.ELEMENT_SEPARATOR_CHAR_ARRAY); - } - - sb.append(N.toString(_columnList.get(j).get(i))); - } - - sb.append("]"); - } - } - - sb.append("]"); - sb.append("}"); - - String str = sb.toString(); - - ObjectFactory.recycle(sb); - - return str; - } - - private void init() { - if (!_initialized) { - initIndexMap(); - - final int rowLength = rowLength(); - final int columnLength = columnLength(); - _columnList = new ArrayList<>(columnLength); - - for (int i = 0; i < columnLength; i++) { - final List column = new ArrayList<>(rowLength); - N.fill(column, 0, rowLength, null); - _columnList.add(column); - } - - _initialized = true; - } - } - - private void initIndexMap() { - if (_rowKeyIndexMap == null || _columnKeyIndexMap == null) { - final int rowLength = rowLength(); - _rowKeyIndexMap = new BiMap<>(N.initHashCapacity(rowLength)); - int index = 0; - for (R rowKey : _rowKeySet) { - _rowKeyIndexMap.put(rowKey, index++); - } - - final int columnLength = columnLength(); - _columnKeyIndexMap = new BiMap<>(N.initHashCapacity(columnLength)); - index = 0; - for (C columnKey : _columnKeySet) { - _columnKeyIndexMap.put(columnKey, index++); - } - } - } - - private void checkRowKey(Object rowKey) { - if (!_rowKeySet.contains(rowKey)) { - throw new IllegalArgumentException("No row found by key: " + rowKey); - } - } - - private void checkColumnKey(Object columnKey) { - if (!_columnKeySet.contains(columnKey)) { - throw new IllegalArgumentException("No column found by key: " + columnKey); - } - } - - private void checkRowIndex(int rowIndex) { - if (rowIndex < 0 || rowIndex >= _rowKeySet.size()) { - throw new IndexOutOfBoundsException("Row index: " + rowIndex + " can't be negative or equals to or bigger than the row size: " + _rowKeySet.size()); - } - } - - private void checkColumnIndex(int columnIndex) { - if (columnIndex < 0 || columnIndex >= _columnKeySet.size()) { - throw new IndexOutOfBoundsException( - "Column index: " + columnIndex + " can't be negative or equals to or bigger than the column size: " + _columnKeySet.size()); - } - } - - private int getRowIndex(Object rowKey) { - if (_rowKeyIndexMap == null) { - this.initIndexMap(); - } - - Integer index = _rowKeyIndexMap.get(rowKey); - - if (index == null) { - throw new IllegalArgumentException("No row found by key: " + rowKey); - } - - return index; - } - - private int getColumnIndex(Object columnKey) { - if (_columnKeyIndexMap == null) { - this.initIndexMap(); - } - - Integer index = _columnKeyIndexMap.get(columnKey); - - if (index == null) { - throw new IllegalArgumentException("No column found by key: " + columnKey); - } - - return index; - } - - private void checkFrozen() { - if (_isFrozen) { - throw new IllegalStateException("This DataSet is frozen, can't modify it."); - } - } - - static class Cell0 implements Sheet.Cell { - private final R rowKey; - private final C columnKey; - private final E value; - - public Cell0(R rowKey, C columnKey, E value) { - this.rowKey = rowKey; - this.columnKey = columnKey; - this.value = value; - } - - @Override - public R rowKey() { - return rowKey; - } - - @Override - public C columnKey() { - return columnKey; - } - - @Override - public E value() { - return value; - } - - @Override - public int hashCode() { - int result = N.hashCode(rowKey); - result = result * 31 + N.hashCode(columnKey); - result = result * 31 + N.hashCode(value); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (obj instanceof Cell0) { - final Cell0 other = (Cell0) obj; - - return N.equals(rowKey, other.rowKey) && N.equals(columnKey, other.columnKey) && N.equals(value, other.value); - } - - return false; - } - - @Override - public String toString() { - return "{rowKey=" + N.toString(rowKey) + ", columnKey=" + N.toString(columnKey) + ", value=" + N.toString(value) + "}"; - } - } -} diff --git a/src/com/landawn/abacus/util/BiMap.java b/src/com/landawn/abacus/util/BiMap.java index c9397ed2..19981850 100644 --- a/src/com/landawn/abacus/util/BiMap.java +++ b/src/com/landawn/abacus/util/BiMap.java @@ -16,7 +16,9 @@ package com.landawn.abacus.util; +import java.util.AbstractSet; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -200,17 +202,71 @@ public boolean containsValue(Object value) { @Override public Set keySet() { - return keyMap.keySet(); + return ImmutableSet.of(keyMap.keySet()); } @Override public Set values() { - return valueMap.keySet(); + return ImmutableSet.of(valueMap.keySet()); } @Override - public Set> entrySet() { - return keyMap.entrySet(); + public Set> entrySet() { + return new AbstractSet>() { + @Override + public Iterator> iterator() { + return new Iterator>() { + private final Iterator> keyValueEntryIter = keyMap.entrySet().iterator(); + + @Override + public boolean hasNext() { + return keyValueEntryIter.hasNext(); + } + + @Override + public Map.Entry next() { + final Map.Entry entry = keyValueEntryIter.next(); + + return new Map.Entry() { + @Override + public K getKey() { + return entry.getKey(); + } + + @Override + public V getValue() { + return entry.getValue(); + } + + @Override + public V setValue(V value) { + if (N.equals(entry.getValue(), value)) { + return entry.getValue(); + } + + // if (valueMap.containsKey(value)) { + // throw new IllegalStateException("Value: " + N.toString(value) + " already existed."); + // } + + valueMap.remove(entry.getValue()); + valueMap.put(value, entry.getKey()); + return entry.setValue(value); + } + }; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Override + public int size() { + return keyMap.size(); + } + }; } @Override diff --git a/src/com/landawn/abacus/util/N.java b/src/com/landawn/abacus/util/N.java index 18f839be..d7948281 100644 --- a/src/com/landawn/abacus/util/N.java +++ b/src/com/landawn/abacus/util/N.java @@ -989,7 +989,7 @@ public int compare(final Comparable a, final Comparable b) { BUILT_IN_TYPE.put(Multimap.class.getCanonicalName(), Multimap.class); BUILT_IN_TYPE.put(Multiset.class.getCanonicalName(), Multiset.class); BUILT_IN_TYPE.put(Sheet.class.getCanonicalName(), Sheet.class); - BUILT_IN_TYPE.put(ArraySheet.class.getCanonicalName(), ArraySheet.class); + BUILT_IN_TYPE.put(Sheet.class.getCanonicalName(), Sheet.class); BUILT_IN_TYPE.put(HBaseColumn.class.getCanonicalName(), HBaseColumn.class); BUILT_IN_TYPE.put(Type.class.getCanonicalName(), Type.class); diff --git a/src/com/landawn/abacus/util/Sheet.java b/src/com/landawn/abacus/util/Sheet.java index e1b5769c..dfaff652 100644 --- a/src/com/landawn/abacus/util/Sheet.java +++ b/src/com/landawn/abacus/util/Sheet.java @@ -16,15 +16,24 @@ package com.landawn.abacus.util; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; import com.landawn.abacus.DataSet; -import com.landawn.abacus.annotation.Beta; +import com.landawn.abacus.core.RowDataSet; +import com.landawn.abacus.parser.KryoParser; +import com.landawn.abacus.parser.ParserFactory; import com.landawn.abacus.util.function.BiFunction; import com.landawn.abacus.util.function.Function; +import com.landawn.abacus.util.stream.ImmutableIterator; import com.landawn.abacus.util.stream.Stream; /** @@ -33,35 +42,469 @@ * * @author Haiyang Li */ -public interface Sheet { +public final class Sheet { + private static final KryoParser kryoParser = ParserFactory.isKryoAvailable() ? ParserFactory.createKryoParser() : null; + + private final Set _rowKeySet; + private final Set _columnKeySet; + private BiMap _rowKeyIndexMap; + private BiMap _columnKeyIndexMap; + private List> _columnList; + private boolean _initialized = false; + private boolean _isFrozen = false; + + // For Kryo. + Sheet() { + this(N.EMPTY_LIST, N.EMPTY_LIST); + } + + public Sheet(Collection rowKeySet, Collection columnKeySet) { + this._rowKeySet = new LinkedHashSet<>(rowKeySet); + this._columnKeySet = new LinkedHashSet<>(columnKeySet); + } + + public Sheet(Collection rowKeySet, Collection columnKeySet, Object[][] rows) { + this(rowKeySet, columnKeySet); + + final int rowLength = this._rowKeySet.size(); + final int columnLength = this._columnKeySet.size(); + + if (N.notNullOrEmpty(rows)) { + N.checkArgument(rows.length == rowLength, "The length of array is not equal to size of row/column key set"); + + for (Object[] e : rows) { + N.checkArgument(e.length == columnLength, "The length of array is not equal to size of row/column key set"); + } + + initIndexMap(); + + _columnList = new ArrayList<>(columnLength); + + for (int i = 0; i < columnLength; i++) { + final List column = new ArrayList<>(rowLength); + + for (int j = 0; j < rowLength; j++) { + column.add((E) rows[j][i]); + } + + _columnList.add(column); + } + + _initialized = true; + } + } + + public static Sheet of(Collection rowKeySet, Collection columnKeySet, Object[][] rows) { + return new Sheet<>(rowKeySet, columnKeySet, rows); + } + + public static Sheet of(Collection rowKeySet, Collection columnKeySet, Collection> rows) { + final Sheet instance = new Sheet<>(rowKeySet, columnKeySet); + + final int rowLength = instance._rowKeySet.size(); + final int columnLength = instance._columnKeySet.size(); + + if (N.notNullOrEmpty(rows)) { + N.checkArgument(rows.size() == rowLength, "The size of collection is not equal to size of row/column key set"); + + for (Collection e : rows) { + N.checkArgument(e.size() == columnLength, "The size of collection is not equal to size of row/column key set"); + } + + instance.initIndexMap(); + + instance._columnList = new ArrayList<>(columnLength); + + for (int i = 0; i < columnLength; i++) { + instance._columnList.add(new ArrayList(rowLength)); + } + + for (Collection row : rows) { + final Iterator iter = row.iterator(); - Set rowKeySet(); + for (int i = 0; i < columnLength; i++) { + instance._columnList.get(i).add(iter.next()); + } + } - Set columnKeySet(); + instance._initialized = true; + } - E get(Object rowKey, Object columnKey); + return instance; - E put(R rowKey, C columnKey, E value); + } + + public static Sheet from(Collection rowKeySet, Collection columnKeySet, Object[][] columns) { + final Sheet instance = new Sheet<>(rowKeySet, columnKeySet); + + final int rowLength = instance._rowKeySet.size(); + final int columnLength = instance._columnKeySet.size(); + + if (N.notNullOrEmpty(columns)) { + N.checkArgument(columns.length == columnLength, "The length of array is not equal to size of row/column key set"); + + for (Object[] e : columns) { + N.checkArgument(e.length == rowLength, "The length of array is not equal to size of row/column key set"); + } + + instance.initIndexMap(); + + instance._columnList = new ArrayList<>(columnLength); + + for (Object[] column : columns) { + instance._columnList.add(new ArrayList<>((List) Arrays.asList(column))); + } + + instance._initialized = true; + } + + return instance; + } + + public static Sheet from(Collection rowKeySet, Collection columnKeySet, Collection> columns) { + final Sheet instance = new Sheet<>(rowKeySet, columnKeySet); - void putAll(Sheet source); + final int rowLength = instance._rowKeySet.size(); + final int columnLength = instance._columnKeySet.size(); - E remove(Object rowKey, Object columnKey); + if (N.notNullOrEmpty(columns)) { + N.checkArgument(columns.size() == columnLength, "The size of collection is not equal to size of row/column key set"); - boolean contains(Object rowKey, Object columnKey); + for (Collection e : columns) { + N.checkArgument(e.size() == rowLength, "The size of collection is not equal to size of row/column key set"); + } - boolean containsValue(Object value); + instance.initIndexMap(); - List getRow(Object rowKey); + instance._columnList = new ArrayList<>(columnLength); - void setRow(R rowKey, Collection row); + for (Collection column : columns) { + instance._columnList.add(new ArrayList<>(column)); + } - void addRow(R rowKey, Collection row); + instance._initialized = true; + } - void addRow(int rowIndex, R rowKey, Collection row); + return instance; + } + + public Set rowKeySet() { + return _rowKeySet; + } + + public Set columnKeySet() { + return _columnKeySet; + } + + public E get(Object rowKey, Object columnKey) { + if (_initialized) { + final int rowIndex = getRowIndex(rowKey); + final int columnIndex = getColumnIndex(columnKey); - void updateRow(R rowKey, Function func); + return get(rowIndex, columnIndex); + } else { + checkRowKey(rowKey); + checkColumnKey(columnKey); - void removeRow(Object rowKey); + return null; + } + } + + /** + * + * @param rowIndex + * @param columnIndex + * @return + */ + public E get(int rowIndex, int columnIndex) { + if (_initialized) { + return _columnList.get(columnIndex).get(rowIndex); + } else { + checkRowIndex(rowIndex); + checkColumnIndex(columnIndex); + + return null; + } + } + + public E put(R rowKey, C columnKey, E value) { + checkFrozen(); + + init(); + + final int rowIndex = getRowIndex(rowKey); + final int columnIndex = getColumnIndex(columnKey); + + return put(rowIndex, columnIndex, value); + } + + public E put(int rowIndex, int columnIndex, E value) { + checkFrozen(); + + init(); + + final Object previousValue = _columnList.get(columnIndex).get(rowIndex); + _columnList.get(columnIndex).set(rowIndex, value); + + return (E) previousValue; + } + + public void putAll(Sheet source) { + checkFrozen(); + + if (!this.rowKeySet().containsAll(source.rowKeySet())) { + throw new IllegalArgumentException(source.rowKeySet() + " are not all included in this sheet with row key set: " + this.rowKeySet()); + } + + if (!this.columnKeySet().containsAll(source.columnKeySet())) { + throw new IllegalArgumentException(source.columnKeySet() + " are not all included in this sheet with column key set: " + this.columnKeySet()); + } + + final Sheet tmp = (Sheet) source; + for (R r : tmp.rowKeySet()) { + for (C c : tmp.columnKeySet()) { + this.put(r, c, tmp.get(r, c)); + } + } + } + + public E remove(Object rowKey, Object columnKey) { + checkFrozen(); + + if (_initialized) { + final int rowIndex = getRowIndex(rowKey); + final int columnIndex = getColumnIndex(columnKey); + + return remove(rowIndex, columnIndex); + } else { + checkRowKey(rowKey); + checkColumnKey(columnKey); + + return null; + } + } + + public E remove(int rowIndex, int columnIndex) { + checkFrozen(); + + if (_initialized) { + return _columnList.get(columnIndex).set(rowIndex, null); + } else { + checkRowIndex(rowIndex); + checkColumnIndex(columnIndex); + + return null; + } + } + + public boolean contains(Object rowKey, Object columnKey) { + return get(rowKey, columnKey) != null; + } + + public boolean containsValue(Object value) { + // if (value == null) { + // for (R r : rowKeySet()) { + // for (C c : columnKeySet()) { + // if (this.get(r, c) == null) { + // return true; + // } + // } + // } + // } else { + // for (R r : rowKeySet()) { + // for (C c : columnKeySet()) { + // if (value.equals(this.get(r, c))) { + // return true; + // } + // } + // } + // } + // + // return false; + + if (this._initialized) { + for (List column : _columnList) { + if (column.contains(value)) { + return true; + } + } + + return false; + } else { + return value == null; + } + } + + public List getRow(Object rowKey) { + final int columnLength = columnLength(); + final List row = new ArrayList<>(columnLength); + + if (_initialized) { + final int rowIndex = getRowIndex(rowKey); + + for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { + row.add(_columnList.get(columnIndex).get(rowIndex)); + } + } else { + checkRowKey(rowKey); + + N.fill(row, 0, columnLength, null); + } + + return N.asImmutableList(row); + } + + public void setRow(R rowKey, Collection row) { + final int columnLength = columnLength(); + + if (N.notNullOrEmpty(row) && row.size() != columnLength) { + throw new IllegalArgumentException("The size of specified row: " + row.size() + " doesn't match the length of column key set: " + columnLength); + } + + init(); + + final int rowIndex = getRowIndex(rowKey); + + if (N.isNullOrEmpty(row)) { + for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { + _columnList.get(columnIndex).set(rowIndex, null); + } + } else { + final Iterator iter = row.iterator(); + + for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { + _columnList.get(columnIndex).set(rowIndex, iter.next()); + } + } + } + + public void addRow(R rowKey, Collection row) { + checkFrozen(); + + if (_rowKeySet.contains(rowKey)) { + throw new IllegalArgumentException("Row '" + rowKey + "' already existed"); + } + + final int rowLength = rowLength(); + final int columnLength = columnLength(); + + if (N.notNullOrEmpty(row) && row.size() != columnLength) { + throw new IllegalArgumentException("The size of specified row: " + row.size() + " doesn't match the length of column key set: " + columnLength); + } + + init(); + + _rowKeySet.add(rowKey); + _rowKeyIndexMap.put(rowKey, rowLength); + + if (N.isNullOrEmpty(row)) { + for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { + _columnList.get(columnIndex).add(null); + } + } else { + final Iterator iter = row.iterator(); + + for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { + _columnList.get(columnIndex).add(iter.next()); + } + } + } + + public void addRow(final int rowIndex, final R rowKey, final Collection row) { + checkFrozen(); + + final int rowLength = rowLength(); + final int columnLength = columnLength(); + + if (rowIndex == rowLength) { + addRow(rowKey, row); + return; + } + + if (rowIndex < 0 || rowIndex > rowLength) { + throw new IllegalArgumentException("Invalid row index: " + rowIndex + ". It must be: >= 0 and <= " + rowLength); + } + + if (_rowKeySet.contains(rowKey)) { + throw new IllegalArgumentException("Row '" + rowKey + "' already existed"); + } + + if (N.notNullOrEmpty(row) && row.size() != columnLength) { + throw new IllegalArgumentException("The size of specified row: " + row.size() + " doesn't match the length of column key set: " + columnLength); + } + + init(); + + final List tmp = new ArrayList<>(rowLength + 1); + tmp.addAll(_rowKeySet); + tmp.add(rowIndex, rowKey); + + _rowKeySet.clear(); + _rowKeySet.addAll(tmp); + + for (Map.Entry entry : _rowKeyIndexMap.entrySet()) { + if (entry.getValue().intValue() >= rowIndex) { + entry.setValue(entry.getValue() + 1); + } + } + + _rowKeyIndexMap.put(rowKey, rowIndex); + + if (N.isNullOrEmpty(row)) { + for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { + _columnList.get(columnIndex).add(rowIndex, null); + } + } else { + final Iterator iter = row.iterator(); + + for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { + _columnList.get(columnIndex).add(rowIndex, iter.next()); + } + } + + } + + public void updateRow(R rowKey, Function func) { + checkFrozen(); + + if (columnLength() > 0) { + this.init(); + + final int rowIndex = this.getRowIndex(rowKey); + + for (List column : _columnList) { + column.set(rowIndex, func.apply(column.get(rowIndex))); + } + } + } + + public void removeRow(Object rowKey) { + checkFrozen(); + + checkRowKey(rowKey); + + _rowKeySet.remove(rowKey); + + if (_rowKeyIndexMap != null) { + final int columnLength = columnLength(); + final int newRowSize = _rowKeySet.size(); + final int removedRowIndex = _rowKeyIndexMap.remove(rowKey); + + if (removedRowIndex == newRowSize) { + // removed last row. + } else { + for (int i = removedRowIndex; i < newRowSize; i++) { + _rowKeyIndexMap.put(_rowKeyIndexMap.getByValue(i + 1), i); + } + } + + if (_initialized) { + for (int columnIndex = 0; columnIndex < columnLength; columnIndex++) { + _columnList.get(columnIndex).remove(removedRowIndex); + } + } + } + } /** * Move the specified row to the new position. @@ -69,7 +512,27 @@ public interface Sheet { * @param rowKey * @param newRowIndex */ - void moveRow(Object rowKey, int newRowIndex); + public void moveRow(Object rowKey, int newRowIndex) { + checkFrozen(); + + this.checkRowIndex(newRowIndex); + + final int rowIndex = this.getRowIndex(rowKey); + final List tmp = new ArrayList<>(rowLength()); + tmp.addAll(_rowKeySet); + tmp.add(newRowIndex, tmp.remove(rowIndex)); + + _rowKeySet.clear(); + _rowKeySet.addAll(tmp); + + _rowKeyIndexMap = null; + + if (_initialized && _columnList.size() > 0) { + for (List column : _columnList) { + column.add(newRowIndex, column.remove(rowIndex)); + } + } + } /** * Swap the positions of the two specified rows. @@ -77,27 +540,242 @@ public interface Sheet { * @param rowKeyA * @param rowKeyB */ - void swapRow(Object rowKeyA, Object rowKeyB); + public void swapRow(Object rowKeyA, Object rowKeyB) { + checkFrozen(); + + final int rowIndexA = this.getRowIndex(rowKeyA); + final int rowIndexB = this.getRowIndex(rowKeyB); + + final List tmp = new ArrayList<>(rowLength()); + tmp.addAll(_rowKeySet); + final R tmpRowKeyA = tmp.get(rowIndexA); + tmp.set(rowIndexA, tmp.get(rowIndexB)); + tmp.set(rowIndexB, tmpRowKeyA); + + _rowKeySet.clear(); + _rowKeySet.addAll(tmp); + + _rowKeyIndexMap.put(tmp.get(rowIndexA), rowIndexA); + _rowKeyIndexMap.put(tmp.get(rowIndexB), rowIndexB); + + if (_initialized && _columnList.size() > 0) { + E tmpVal = null; + + for (List column : _columnList) { + tmpVal = column.get(rowIndexA); + column.set(rowIndexA, column.get(rowIndexB)); + column.set(rowIndexB, tmpVal); + } + } + } + + public void renameRow(R rowKey, R newRowKey) { + checkFrozen(); + checkRowKey(rowKey); + + if (this._rowKeySet.contains(newRowKey)) { + throw new IllegalArgumentException("Invalid new row key: " + N.toString(newRowKey) + ". It's already in the row key set."); + } + + final int rowIndex = this.getRowIndex(rowKey); + final List tmp = new ArrayList<>(_rowKeySet); + tmp.set(rowIndex, newRowKey); - void renameRow(R rowKey, R newRowKey); + this._rowKeySet.clear(); + this._rowKeySet.addAll(tmp); - boolean containsRow(Object rowKey); + if (N.notNullOrEmpty(this._rowKeyIndexMap)) { + this._rowKeyIndexMap.put(newRowKey, _rowKeyIndexMap.remove(rowKey)); + } + } + + public boolean containsRow(Object rowKey) { + return _rowKeySet.contains(rowKey); + } + + public Map row(Object rowKey) { + final int columnLength = columnLength(); + Map rowMap = new LinkedHashMap<>(N.initHashCapacity(columnLength)); + + if (_initialized) { + final int rowIndex = getRowIndex(rowKey); + int columnIndex = 0; + + for (C columnKey : this.columnKeySet()) { + rowMap.put(columnKey, _columnList.get(columnIndex++).get(rowIndex)); + } + } else { + checkRowKey(rowKey); + + for (C columnKey : this.columnKeySet()) { + rowMap.put(columnKey, null); + } + } + + return rowMap; + } + + public Map> rowMap() { + final Map> result = new LinkedHashMap<>(N.initHashCapacity(this.rowKeySet().size())); + + for (R rowKey : this.rowKeySet()) { + result.put(rowKey, row(rowKey)); + } + + return result; + } + + public List getColumn(Object columnKey) { + final int rowLength = rowLength(); + List column = null; + + if (_initialized) { + column = _columnList.get(getColumnIndex(columnKey)); + } else { + checkColumnKey(columnKey); + column = new ArrayList<>(rowLength); + N.fill(column, 0, rowLength, null); + } + + return N.asImmutableList(column); + } + + public void setColumn(C columnKey, Collection column) { + checkFrozen(); + + final int rowLength = rowLength(); + + if (N.notNullOrEmpty(column) && column.size() != rowLength) { + throw new IllegalArgumentException("The size of specified column: " + column.size() + " doesn't match the length of row key set: " + rowLength); + } + + init(); + + final int columnIndex = getColumnIndex(columnKey); + + if (N.isNullOrEmpty(column)) { + N.fill(_columnList.get(columnIndex), 0, rowLength, null); + } else { + _columnList.set(columnIndex, new ArrayList<>(column)); + } + } - Map row(Object rowKey); + public void addColumn(C columnKey, Collection column) { + checkFrozen(); - Map> rowMap(); + if (_columnKeySet.contains(columnKey)) { + throw new IllegalArgumentException("Column '" + columnKey + "' already existed"); + } - List getColumn(Object columnKey); + final int rowLength = rowLength(); + final int columnLength = columnLength(); + + if (N.notNullOrEmpty(column) && column.size() != rowLength) { + throw new IllegalArgumentException("The size of specified column: " + column.size() + " doesn't match the length of row key set: " + rowLength); + } + + init(); + + _columnKeySet.add(columnKey); + _columnKeyIndexMap.put(columnKey, columnLength); + + if (N.isNullOrEmpty(column)) { + List newColumn = new ArrayList<>(); + N.fill(newColumn, 0, rowLength, null); + _columnList.add(newColumn); + } else { + _columnList.add(new ArrayList<>(column)); + } + } + + public void addColumn(int columnIndex, C columnKey, Collection column) { + checkFrozen(); + + final int rowLength = rowLength(); + final int columnLength = columnLength(); + + if (columnIndex == columnLength) { + addColumn(columnKey, column); + return; + } + + if (columnIndex < 0 || columnIndex > columnLength) { + throw new IllegalArgumentException("Invalid column index: " + columnIndex + ". It must be: >= 0 and <= " + columnLength); + } + + if (_columnKeySet.contains(columnKey)) { + throw new IllegalArgumentException("Column '" + columnKey + "' already existed"); + } + + if (N.notNullOrEmpty(column) && column.size() != rowLength) { + throw new IllegalArgumentException("The size of specified column: " + column.size() + " doesn't match the length of row key set: " + rowLength); + } + + init(); + + final List tmp = new ArrayList<>(columnLength + 1); + tmp.addAll(_columnKeySet); + tmp.add(columnIndex, columnKey); + + _columnKeySet.clear(); + _columnKeySet.addAll(tmp); + + for (Map.Entry entry : _columnKeyIndexMap.entrySet()) { + if (entry.getValue().intValue() >= columnIndex) { + entry.setValue(entry.getValue() + 1); + } + } + + _columnKeyIndexMap.put(columnKey, columnIndex); + + if (N.isNullOrEmpty(column)) { + List newColumn = new ArrayList<>(); + N.fill(newColumn, 0, rowLength, null); + _columnList.add(columnIndex, newColumn); + } else { + _columnList.add(columnIndex, new ArrayList<>(column)); + } + } + + public void updateColumn(C columnKey, Function func) { + checkFrozen(); + + if (rowLength() > 0) { + this.init(); + + final int rowLength = rowLength(); + final List column = _columnList.get(this.getColumnIndex(columnKey)); + + for (int rowIndex = 0; rowIndex < rowLength; rowIndex++) { + column.set(rowIndex, func.apply(column.get(rowIndex))); + } + } + } - void setColumn(C columnKey, Collection column); + public void removeColumn(Object columnKey) { + checkFrozen(); - void addColumn(C columnKey, Collection column); + checkColumnKey(columnKey); - void addColumn(int columnIndex, C columnKey, Collection column); + _columnKeySet.remove(columnKey); - void updateColumn(C columnKey, Function func); + if (_columnKeyIndexMap != null) { + final int newColumnLength = _columnKeySet.size(); + final int removedColumnIndex = _columnKeyIndexMap.remove(columnKey); - void removeColumn(Object columnKey); + if (removedColumnIndex == newColumnLength) { + // removed the last column + } else { + for (int i = removedColumnIndex; i < newColumnLength; i++) { + _columnKeyIndexMap.put(_columnKeyIndexMap.getByValue(i + 1), i); + } + } + + if (_initialized) { + _columnList.remove(removedColumnIndex); + } + } + } /** * Move the specified column to the new position. @@ -105,7 +783,25 @@ public interface Sheet { * @param columnKey * @param newColumnIndex */ - void moveColumn(Object columnKey, int newColumnIndex); + public void moveColumn(Object columnKey, int newColumnIndex) { + checkFrozen(); + + this.checkColumnIndex(newColumnIndex); + + final int columnIndex = this.getColumnIndex(columnKey); + final List tmp = new ArrayList<>(columnLength()); + tmp.addAll(_columnKeySet); + tmp.add(newColumnIndex, tmp.remove(columnIndex)); + + _columnKeySet.clear(); + _columnKeySet.addAll(tmp); + + _columnKeyIndexMap = null; + + if (_initialized && _columnList.size() > 0) { + _columnList.add(newColumnIndex, _columnList.remove(columnIndex)); + } + } /** * Swap the positions of the two specified columns. @@ -113,101 +809,432 @@ public interface Sheet { * @param columnKeyA * @param columnKeyB */ - void swapColumn(Object columnKeyA, Object columnKeyB); + public void swapColumn(Object columnKeyA, Object columnKeyB) { + checkFrozen(); + + final int columnIndexA = this.getColumnIndex(columnKeyA); + final int columnIndexB = this.getColumnIndex(columnKeyB); + + final List tmp = new ArrayList<>(rowLength()); + tmp.addAll(_columnKeySet); + final C tmpColumnKeyA = tmp.get(columnIndexA); + tmp.set(columnIndexA, tmp.get(columnIndexB)); + tmp.set(columnIndexB, tmpColumnKeyA); + + _columnKeySet.clear(); + _columnKeySet.addAll(tmp); + + _columnKeyIndexMap.put(tmp.get(columnIndexA), columnIndexA); + _columnKeyIndexMap.put(tmp.get(columnIndexB), columnIndexB); + + if (_initialized && _columnList.size() > 0) { + final List tmpColumnA = _columnList.get(columnIndexA); + + _columnList.set(columnIndexA, _columnList.get(columnIndexB)); + _columnList.set(columnIndexB, tmpColumnA); + } + } + + public void renameColumn(C columnKey, C newColumnKey) { + checkFrozen(); + + this.checkColumnKey(columnKey); + + if (this._columnKeySet.contains(newColumnKey)) { + throw new IllegalArgumentException("Invalid new column key: " + N.toString(newColumnKey) + ". It's already in the column key set."); + } + + final int columnIndex = this.getColumnIndex(columnKey); + final List tmp = new ArrayList<>(_columnKeySet); + tmp.set(columnIndex, newColumnKey); + + this._columnKeySet.clear(); + this._columnKeySet.addAll(tmp); + + if (N.notNullOrEmpty(this._columnKeyIndexMap)) { + this._columnKeyIndexMap.put(newColumnKey, _columnKeyIndexMap.remove(columnKey)); + } + } + + public boolean containsColumn(Object columnKey) { + return _columnKeySet.contains(columnKey); + } - void renameColumn(C columnKey, C newColumnKey); + public Map column(Object columnKey) { + final int rowLength = rowLength(); + final Map columnMap = new LinkedHashMap<>(N.initHashCapacity(rowLength)); - boolean containsColumn(Object columnKey); + if (_initialized) { + final int columnIndex = getColumnIndex(columnKey); + final List column = _columnList.get(columnIndex); + int rowIndex = 0; - Map column(Object columnKey); + for (R rowKey : this.rowKeySet()) { + columnMap.put(rowKey, column.get(rowIndex++)); + } + } else { + checkColumnKey(columnKey); - Map> columnMap(); + for (R rowKey : this.rowKeySet()) { + columnMap.put(rowKey, null); + } + } + + return columnMap; + } + + public Map> columnMap() { + final Map> result = new LinkedHashMap<>(N.initHashCapacity(this.columnKeySet().size())); + + for (C columnKey : this.columnKeySet()) { + result.put(columnKey, column(columnKey)); + } + + return result; + } /** * Returns the size of row key set. * * @return */ - int rowLength(); + public int rowLength() { + return _rowKeySet.size(); + } /** * Returns the size of column key set. * * @return */ - int columnLength(); + public int columnLength() { + return _columnKeySet.size(); + } + + public void updateAll(Function func) { + checkFrozen(); + + if (rowLength() > 0 && columnLength() > 0) { + this.init(); + + final int rowLength = rowLength(); + + for (List column : _columnList) { + for (int rowIndex = 0; rowIndex < rowLength; rowIndex++) { + column.set(rowIndex, func.apply(column.get(rowIndex))); + } + } + } + } + + public Sheet copy() { + final Sheet copy = new Sheet<>(this._rowKeySet, this._columnKeySet); + + if (this._initialized) { + copy.initIndexMap(); + + copy._columnList = new ArrayList<>(_columnList.size()); + + for (List column : _columnList) { + copy._columnList.add(new ArrayList<>(column)); + } + + copy._initialized = true; + } + + return copy; + } + + public Sheet copy(Collection rowKeySet, Collection columnKeySet) { + if (this._rowKeySet.containsAll(rowKeySet) == false) { + throw new IllegalArgumentException( + "Row keys: " + N.difference(rowKeySet, this._rowKeySet) + " are not included in this sheet row keys: " + this._rowKeySet); + } + + if (this._columnKeySet.containsAll(columnKeySet) == false) { + throw new IllegalArgumentException( + "Column keys: " + N.difference(columnKeySet, this._columnKeySet) + " are not included in this sheet Column keys: " + this._columnKeySet); + } + + final Sheet copy = new Sheet<>(rowKeySet, columnKeySet); - void updateAll(Function func); + if (this._initialized) { + copy.initIndexMap(); - Sheet copy(); + copy._columnList = new ArrayList<>(copy._columnKeySet.size()); - Sheet copy(Collection rowKeySet, Collection columnKeySet); + final int[] rowKeyIndices = new int[copy._rowKeySet.size()]; + int idx = 0; + + for (R rowKey : copy._rowKeySet) { + rowKeyIndices[idx++] = this.getRowIndex(rowKey); + } + + for (C columnKey : copy._columnKeySet) { + final List column = _columnList.get(this.getColumnIndex(columnKey)); + final List newColumn = new ArrayList<>(rowKeyIndices.length); + + for (int rowIndex : rowKeyIndices) { + newColumn.add(column.get(rowIndex)); + } + + copy._columnList.add(newColumn); + } + + copy._initialized = true; + } + + return copy; + } /** * Deeply copy each element in this Sheet by Serialization/Deserialization. * * @return */ - Sheet clone(); + @Override + public Sheet clone() { + return clone(this._isFrozen); + } /** * Deeply copy each element in this Sheet by Serialization/Deserialization. * * @return */ - Sheet clone(boolean freeze); + public Sheet clone(boolean freeze) { + if (kryoParser == null) { + throw new RuntimeException("Kryo is required"); + } - Sheet merge(Sheet source, BiFunction mergeFunction); + final Sheet copy = kryoParser.clone(this); - Sheet transpose(); + copy._isFrozen = freeze; - /** - * Method freeze - */ - void freeze(); + return copy; + } - /** - * Method frozen - * - * @return - */ - boolean frozen(); + public Sheet merge(Sheet source, BiFunction mergeFunction) { + final Sheet result = this.copy(); + + for (R rowKey : source.rowKeySet()) { + if (result.containsRow(rowKey) == false) { + result.addRow(rowKey, null); + } + } + + for (C columnKey : source.columnKeySet()) { + if (result.containsColumn(columnKey) == false) { + result.addColumn(columnKey, null); + } + } + + final int[] rowKeyIndexes = new int[source.rowLength()]; + final int[] columnKeyIndexes = new int[source.columnLength()]; - void clear(); + int idx = 0; + for (R rowKey : source.rowKeySet()) { + rowKeyIndexes[idx++] = result.getRowIndex(rowKey); + } + + idx = 0; + for (C columnKey : source.columnKeySet()) { + columnKeyIndexes[idx++] = result.getColumnIndex(columnKey); + } + + final Iterator iter = source.columnKeySet().iterator(); + + for (int columnIndex = 0, columnLength = columnKeyIndexes.length; columnIndex < columnLength; columnIndex++) { + final List srcColumn = source.getColumn(iter.next()); + final List targetColumn = result._columnList.get(columnKeyIndexes[columnIndex]); + + for (int rowIndex = 0, rowLength = rowKeyIndexes.length; rowIndex < rowLength; rowIndex++) { + targetColumn.set(rowKeyIndexes[rowIndex], mergeFunction.apply(targetColumn.get(rowKeyIndexes[rowIndex]), srcColumn.get(rowIndex))); + } + } + + return result; + } - void trimToSize(); + public Sheet transpose() { + final Sheet copy = new Sheet<>(this._columnKeySet, this._rowKeySet); + + if (this._initialized) { + copy.initIndexMap(); + + final int rowLength = copy.rowLength(); + final int columnLength = copy.columnLength(); + + copy._columnList = new ArrayList<>(columnLength); + + for (int i = 0; i < columnLength; i++) { + final List column = new ArrayList<>(rowLength); + + for (int j = 0; j < rowLength; j++) { + column.add(_columnList.get(j).get(i)); + } + + copy._columnList.add(column); + } + + copy._initialized = true; + } + + return copy; + } + + public void freeze() { + _isFrozen = true; + } + + public boolean frozen() { + return _isFrozen; + } + + public void clear() { + checkFrozen(); + + if (_initialized && _columnList.size() > 0) { + for (List column : _columnList) { + N.fill(column, 0, column.size(), null); + } + } + } + + public void trimToSize() { + if (_initialized && _columnList.size() > 0) { + for (List column : _columnList) { + if (column instanceof ArrayList) { + ((ArrayList) column).trimToSize(); + } + } + } + } /** * * @return a stream of Cells based on the order of row. */ - Stream> cells(); + public Stream> cells() { + return cells(0, _rowKeySet.size()); + } /** * + * @param fromRowIndex + * @param toRowIndex * @return a stream of Cells based on the order of row. */ - Stream> cells(int fromRowIndex, int toRowIndex); + public Stream> cells(final int fromRowIndex, final int toRowIndex) { + N.checkIndex(fromRowIndex, toRowIndex, _rowKeySet.size()); + + if (_rowKeySet.size() == 0 || _columnKeySet.size() == 0) { + return Stream.empty(); + } + + initIndexMap(); + + return Stream.of(new ImmutableIterator>() { + private final int columnLength = columnLength(); + private final long toIndex = toRowIndex * columnLength * 1L; + private long cursor = fromRowIndex * columnLength * 1L; + + @Override + public boolean hasNext() { + return cursor < toIndex; + } + + @Override + public Sheet.Cell next() { + if (cursor >= toIndex) { + throw new NoSuchElementException(); + } + + final int rowIndex = (int) (cursor / columnLength); + final int columnIndex = (int) (cursor++ % columnLength); + + return new Cell0<>(_rowKeyIndexMap.getByValue(rowIndex), _columnKeyIndexMap.getByValue(columnIndex), + _initialized ? _columnList.get(columnIndex).get(rowIndex) : null); + } + + @Override + public void skip(long n) { + cursor = n < toIndex - cursor ? cursor + n : toIndex; + } + + @Override + public long count() { + return toIndex - cursor; + } + }); + } /** * * @return a stream of Cells based on the order of column. */ - @Beta - Stream> cells0(); + public Stream> cells0() { + return cells0(0, _columnKeySet.size()); + } /** * + * @param fromColumnIndex + * @param toColumnIndex * @return a stream of Cells based on the order of column. */ - @Beta - Stream> cells0(int fromColumnIndex, int toColumnIndex); + + public Stream> cells0(final int fromColumnIndex, final int toColumnIndex) { + N.checkIndex(fromColumnIndex, toColumnIndex, _columnKeySet.size()); + + if (_rowKeySet.size() == 0 || _columnKeySet.size() == 0) { + return Stream.empty(); + } + + initIndexMap(); + + return Stream.of(new ImmutableIterator>() { + private final int rowLength = rowLength(); + private final long toIndex = toColumnIndex * rowLength * 1L; + private long cursor = fromColumnIndex * rowLength * 1L; + + @Override + public boolean hasNext() { + return cursor < toIndex; + } + + @Override + public Sheet.Cell next() { + if (cursor >= toIndex) { + throw new NoSuchElementException(); + } + + final int rowIndex = (int) (cursor % rowLength); + final int columnIndex = (int) (cursor++ / rowLength); + + return new Cell0<>(_rowKeyIndexMap.getByValue(rowIndex), _columnKeyIndexMap.getByValue(columnIndex), + _initialized ? _columnList.get(columnIndex).get(rowIndex) : null); + } + + @Override + public void skip(long n) { + cursor = n < toIndex - cursor ? cursor + n : toIndex; + } + + @Override + public long count() { + return toIndex - cursor; + } + }); + } /** * * @return a stream based on the order of row. */ - Stream stream(); + public Stream stream() { + return stream(0, _rowKeySet.size()); + } /** * @@ -215,14 +1242,56 @@ public interface Sheet { * @param toRowIndex * @return a stream based on the order of row. */ - Stream stream(int fromRowIndex, int toRowIndex); + public Stream stream(final int fromRowIndex, final int toRowIndex) { + N.checkIndex(fromRowIndex, toRowIndex, _rowKeySet.size()); + + if (_rowKeySet.size() == 0 || _columnKeySet.size() == 0) { + return Stream.empty(); + } + + return Stream.of(new ImmutableIterator() { + private final int columnLength = columnLength(); + private final long toIndex = toRowIndex * columnLength * 1L; + private long cursor = fromRowIndex * columnLength * 1L; + + @Override + public boolean hasNext() { + return cursor < toIndex; + } + + @Override + public E next() { + if (cursor >= toIndex) { + throw new NoSuchElementException(); + } + + if (_initialized) { + return _columnList.get((int) (cursor % columnLength)).get((int) (cursor++ / columnLength)); + } else { + cursor++; + return null; + } + } + + @Override + public void skip(long n) { + cursor = n < toIndex - cursor ? cursor + n : toIndex; + } + + @Override + public long count() { + return toIndex - cursor; + } + }); + } /** * * @return a stream based on the order of column. */ - @Beta - Stream stream0(); + public Stream stream0() { + return stream0(0, _columnKeySet.size()); + } /** * @@ -230,96 +1299,651 @@ public interface Sheet { * @param toColumnIndex * @return a stream based on the order of column. */ - @Beta - Stream stream0(int fromColumnIndex, int toColumnIndex); + public Stream stream0(final int fromColumnIndex, final int toColumnIndex) { + N.checkIndex(fromColumnIndex, toColumnIndex, _columnKeySet.size()); + + if (_rowKeySet.size() == 0 || _columnKeySet.size() == 0) { + return Stream.empty(); + } + + return Stream.of(new ImmutableIterator() { + private final int rowLength = rowLength(); + private final long toIndex = toColumnIndex * rowLength * 1L; + private long cursor = fromColumnIndex * rowLength * 1L; + + @Override + public boolean hasNext() { + return cursor < toIndex; + } + + @Override + public E next() { + if (cursor >= toIndex) { + throw new NoSuchElementException(); + } + + if (_initialized) { + return _columnList.get((int) (cursor / rowLength)).get((int) (cursor++ % rowLength)); + } else { + cursor++; + return null; + } + } + + @Override + public void skip(long n) { + cursor = n < toIndex - cursor ? cursor + n : toIndex; + } + + @Override + public long count() { + return toIndex - cursor; + } + }); + } /** * - * @return a row stream based on the order of row. + * @return a stream based on the order of row. */ - Stream> stream2(); + public Stream> stream2() { + return stream2(0, _rowKeySet.size()); + } /** * * @param fromRowIndex * @param toRowIndex - * @return a row stream based on the order of row. + * @return a stream based on the order of row. */ - Stream> stream2(int fromRowIndex, int toRowIndex); + public Stream> stream2(final int fromRowIndex, final int toRowIndex) { + N.checkIndex(fromRowIndex, toRowIndex, _rowKeySet.size()); + + if (_rowKeySet.size() == 0 || _columnKeySet.size() == 0) { + return Stream.empty(); + } + + return Stream.of(new ImmutableIterator>() { + private final int toIndex = toRowIndex; + private volatile int cursor = fromRowIndex; + + @Override + public boolean hasNext() { + return cursor < toIndex; + } + + @Override + public Stream next() { + if (cursor >= toIndex) { + throw new NoSuchElementException(); + } + + return Stream.of(new ImmutableIterator() { + private final int rowIndex = cursor++; + private final int toIndex2 = _columnKeySet.size(); + private int cursor2 = 0; + + @Override + public boolean hasNext() { + return cursor2 < toIndex2; + } + + @Override + public E next() { + if (cursor2 >= toIndex2) { + throw new NoSuchElementException(); + } + + if (_initialized) { + return _columnList.get(cursor2++).get(rowIndex); + } else { + cursor2++; + return null; + } + } + + @Override + public void skip(long n) { + cursor2 = n < toIndex2 - cursor2 ? cursor2 + (int) n : toIndex2; + } + + @Override + public long count() { + return toIndex2 - cursor2; + } + }); + } + + @Override + public void skip(long n) { + cursor = n < toIndex - cursor ? cursor + (int) n : toIndex; + } + + @Override + public long count() { + return toIndex - cursor; + } + }); + } /** * - * @return a column stream based on the order of column. + * @return a stream based on the order of column. */ - @Beta - Stream> stream02(); + public Stream> stream02() { + return stream02(0, _columnKeySet.size()); + } /** * * @param fromColumnIndex * @param toColumnIndex - * @return a column stream based on the order of column. + * @return a stream based on the order of column. */ - @Beta - Stream> stream02(int fromColumnIndex, int toColumnIndex); + public Stream> stream02(final int fromColumnIndex, final int toColumnIndex) { + N.checkIndex(fromColumnIndex, toColumnIndex, _columnKeySet.size()); + + if (_rowKeySet.size() == 0 || _columnKeySet.size() == 0) { + return Stream.empty(); + } + + return Stream.of(new ImmutableIterator>() { + private final int toIndex = toColumnIndex; + private int cursor = fromColumnIndex; + + @Override + public boolean hasNext() { + return cursor < toIndex; + } + + @Override + public Stream next() { + if (cursor >= toIndex) { + throw new NoSuchElementException(); + } + + if (_initialized) { + return Stream.of(_columnList.get(cursor++)); + } else { + cursor++; + return Stream.repeat(null, rowLength()); + } + } + + @Override + public void skip(long n) { + cursor = n < toIndex - cursor ? cursor + (int) n : toIndex; + } + + @Override + public long count() { + return toIndex - cursor; + } + }); + } /** * * @return a DataSet based on row. */ - DataSet toDataSet(); + public DataSet toDataSet() { + final int rowLength = rowLength(); + final int columnLength = columnLength(); + final List dataSetColumnNameList = new ArrayList<>(columnLength); + + for (C columnKey : _columnKeySet) { + dataSetColumnNameList.add(N.toString(columnKey)); + } + + final List> dataSetColumnList = new ArrayList<>(columnLength); + + if (_initialized) { + for (List column : _columnList) { + dataSetColumnList.add(new ArrayList(column)); + } + } else { + for (int i = 0; i < columnLength; i++) { + List column = new ArrayList<>(rowLength); + N.fill(column, 0, rowLength, null); + dataSetColumnList.add(column); + } + } + + return new RowDataSet(dataSetColumnNameList, dataSetColumnList); + } /** * * @return a DataSet based on column. */ - @Beta - DataSet toDataSet0(); + public DataSet toDataSet0() { + final int rowLength = rowLength(); + final int columnLength = columnLength(); + final List dataSetColumnNameList = new ArrayList<>(rowLength); + + for (R rowKey : _rowKeySet) { + dataSetColumnNameList.add(N.toString(rowKey)); + } + + final List> dataSetColumnList = new ArrayList<>(rowLength); + + if (_initialized) { + for (int i = 0; i < rowLength; i++) { + final List column = new ArrayList<>(columnLength); + + for (int j = 0; j < columnLength; j++) { + column.add(_columnList.get(j).get(i)); + } + + dataSetColumnList.add(column); + } + } else { + for (int i = 0; i < rowLength; i++) { + List column = new ArrayList<>(columnLength); + N.fill(column, 0, columnLength, null); + dataSetColumnList.add(column); + } + } + + return new RowDataSet(dataSetColumnNameList, dataSetColumnList); + } /** * * @param cls * @return a Matrix based on row. */ - Matrix toMatrix(Class cls); + public Matrix toMatrix(Class cls) { + final int rowLength = rowLength(); + final int columnLength = columnLength(); + final E[][] c = N.newArray(N.newArray(cls, 0).getClass(), rowLength); + + for (int i = 0; i < rowLength; i++) { + c[i] = N.newArray(cls, columnLength); + } + + if (rowLength == 0 || columnLength == 0 || _initialized == false) { + return new Matrix<>(c); + } + + for (int i = 0; i < columnLength; i++) { + final List column = _columnList.get(i); + + for (int j = 0; j < rowLength; j++) { + c[j][i] = column.get(j); + } + } + + return new Matrix<>(c); + } /** * * @param cls * @return a Matrix based on column. */ - @Beta - Matrix toMatrix0(Class cls); + public Matrix toMatrix0(Class cls) { + final int rowLength = rowLength(); + final int columnLength = columnLength(); + final E[][] c = N.newArray(N.newArray(cls, 0).getClass(), columnLength); + + for (int i = 0; i < columnLength; i++) { + c[i] = N.newArray(cls, rowLength); + } + + if (rowLength == 0 || columnLength == 0 || _initialized == false) { + return new Matrix<>(c); + } + + for (int i = 0; i < columnLength; i++) { + final List column = _columnList.get(i); + + for (int j = 0; j < rowLength; j++) { + c[i][j] = column.get(j); + } + } + + return new Matrix<>(c); + } /** * * @return a 2D array based on row. */ - Object[][] toArray(); + public Object[][] toArray() { + final int rowLength = rowLength(); + final int columnLength = columnLength(); + final Object[][] copy = new Object[rowLength][columnLength]; + + if (_initialized) { + for (int i = 0; i < columnLength; i++) { + final List column = _columnList.get(i); + + for (int j = 0; j < rowLength; j++) { + copy[j][i] = column.get(j); + } + } + } + + return copy; + } /** * * @return a 2D array based on row. */ - T[][] toArray(Class cls); + public T[][] toArray(Class cls) { + final int rowLength = rowLength(); + final int columnLength = columnLength(); + final T[][] copy = N.newArray(N.newArray(cls, 0).getClass(), rowLength); + + for (int i = 0; i < rowLength; i++) { + copy[i] = N.newArray(cls, columnLength); + } + + if (_initialized) { + for (int i = 0; i < columnLength; i++) { + final List column = _columnList.get(i); + + for (int j = 0; j < rowLength; j++) { + copy[j][i] = (T) column.get(j); + } + } + } + + return copy; + } /** * * @return a 2D array based on column. */ - @Beta - Object[][] toArray0(); + public Object[][] toArray0() { + final int rowLength = rowLength(); + final int columnLength = columnLength(); + final Object[][] copy = new Object[columnLength][rowLength]; + + if (_initialized) { + for (int i = 0; i < columnLength; i++) { + final List column = _columnList.get(i); + + for (int j = 0; j < rowLength; j++) { + copy[i][j] = column.get(j); + } + } + } + + return copy; + } /** * - * @return a 2D array based on row. + * @return a 2D array based on column. */ - @Beta - T[][] toArray0(Class cls); + public T[][] toArray0(Class cls) { + final int rowLength = rowLength(); + final int columnLength = columnLength(); + final T[][] copy = N.newArray(N.newArray(cls, 0).getClass(), columnLength); + + for (int i = 0; i < columnLength; i++) { + copy[i] = N.newArray(cls, rowLength); + } + + if (_initialized) { + for (int i = 0; i < columnLength; i++) { + final List column = _columnList.get(i); + + for (int j = 0; j < rowLength; j++) { + copy[i][j] = (T) column.get(j); + } + } + } + + return copy; + } + + public void println() { + final int columnLength = columnLength(); + N.println(Joiner.with(", ", " ", "").join(_columnKeySet).toString()); + + int i = 0; + for (R rowKey : _rowKeySet) { + final Joiner joiner = Joiner.with(", "); + joiner.add(rowKey); + + if (this._initialized) { + for (int j = 0; j < columnLength; j++) { + joiner.add(_columnList.get(j).get(i)); + } + } else { + for (int j = 0; j < columnLength; j++) { + joiner.add(N.NULL_STRING); + } + } + + i++; + + N.println(joiner.toString()); + } + } - void println(); + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((_rowKeySet == null) ? 0 : _rowKeySet.hashCode()); + result = prime * result + ((_columnKeySet == null) ? 0 : _columnKeySet.hashCode()); + result = prime * result + (_initialized ? _columnList.hashCode() : 0); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj instanceof Sheet) { + Sheet other = (Sheet) obj; + + return N.equals(other._rowKeySet, _rowKeySet) && N.equals(other._columnKeySet, _columnKeySet) && N.deepEquals(other._columnList, _columnList); + } + + return false; + } + + @Override + public String toString() { + final StringBuilder sb = ObjectFactory.createStringBuilder(); + + sb.append("{rowKeySet="); + sb.append(_rowKeySet); + sb.append(", columnKeySet="); + sb.append(_columnKeySet); + sb.append(", rowList="); + sb.append("["); + + if (_initialized) { + for (int i = 0, rowLength = _rowKeySet.size(), columnLength = _columnKeySet.size(); i < rowLength; i++) { + if (i > 0) { + sb.append(N.ELEMENT_SEPARATOR_CHAR_ARRAY); + } + + sb.append("["); + + for (int j = 0; j < columnLength; j++) { + if (j > 0) { + sb.append(N.ELEMENT_SEPARATOR_CHAR_ARRAY); + } + + sb.append(N.toString(_columnList.get(j).get(i))); + } + + sb.append("]"); + } + } + + sb.append("]"); + sb.append("}"); + + String str = sb.toString(); + + ObjectFactory.recycle(sb); + + return str; + } + + private void init() { + if (!_initialized) { + initIndexMap(); + + final int rowLength = rowLength(); + final int columnLength = columnLength(); + _columnList = new ArrayList<>(columnLength); + + for (int i = 0; i < columnLength; i++) { + final List column = new ArrayList<>(rowLength); + N.fill(column, 0, rowLength, null); + _columnList.add(column); + } + + _initialized = true; + } + } + + private void initIndexMap() { + if (_rowKeyIndexMap == null || _columnKeyIndexMap == null) { + final int rowLength = rowLength(); + _rowKeyIndexMap = new BiMap<>(N.initHashCapacity(rowLength)); + int index = 0; + for (R rowKey : _rowKeySet) { + _rowKeyIndexMap.put(rowKey, index++); + } + + final int columnLength = columnLength(); + _columnKeyIndexMap = new BiMap<>(N.initHashCapacity(columnLength)); + index = 0; + for (C columnKey : _columnKeySet) { + _columnKeyIndexMap.put(columnKey, index++); + } + } + } + + private void checkRowKey(Object rowKey) { + if (!_rowKeySet.contains(rowKey)) { + throw new IllegalArgumentException("No row found by key: " + rowKey); + } + } + + private void checkColumnKey(Object columnKey) { + if (!_columnKeySet.contains(columnKey)) { + throw new IllegalArgumentException("No column found by key: " + columnKey); + } + } + + private void checkRowIndex(int rowIndex) { + if (rowIndex < 0 || rowIndex >= _rowKeySet.size()) { + throw new IndexOutOfBoundsException("Row index: " + rowIndex + " can't be negative or equals to or bigger than the row size: " + _rowKeySet.size()); + } + } + + private void checkColumnIndex(int columnIndex) { + if (columnIndex < 0 || columnIndex >= _columnKeySet.size()) { + throw new IndexOutOfBoundsException( + "Column index: " + columnIndex + " can't be negative or equals to or bigger than the column size: " + _columnKeySet.size()); + } + } + + private int getRowIndex(Object rowKey) { + if (_rowKeyIndexMap == null) { + this.initIndexMap(); + } + + Integer index = _rowKeyIndexMap.get(rowKey); + + if (index == null) { + throw new IllegalArgumentException("No row found by key: " + rowKey); + } + + return index; + } + + private int getColumnIndex(Object columnKey) { + if (_columnKeyIndexMap == null) { + this.initIndexMap(); + } + + Integer index = _columnKeyIndexMap.get(columnKey); + + if (index == null) { + throw new IllegalArgumentException("No column found by key: " + columnKey); + } + + return index; + } + + private void checkFrozen() { + if (_isFrozen) { + throw new IllegalStateException("This DataSet is frozen, can't modify it."); + } + } + + static class Cell0 implements Sheet.Cell { + private final R rowKey; + private final C columnKey; + private final E value; + + public Cell0(R rowKey, C columnKey, E value) { + this.rowKey = rowKey; + this.columnKey = columnKey; + this.value = value; + } + + @Override + public R rowKey() { + return rowKey; + } + + @Override + public C columnKey() { + return columnKey; + } + + @Override + public E value() { + return value; + } + + @Override + public int hashCode() { + int result = N.hashCode(rowKey); + result = result * 31 + N.hashCode(columnKey); + result = result * 31 + N.hashCode(value); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj instanceof Cell0) { + final Cell0 other = (Cell0) obj; + + return N.equals(rowKey, other.rowKey) && N.equals(columnKey, other.columnKey) && N.equals(value, other.value); + } + + return false; + } + + @Override + public String toString() { + return "{rowKey=" + N.toString(rowKey) + ", columnKey=" + N.toString(columnKey) + ", value=" + N.toString(value) + "}"; + } + } - public interface Cell { + public static interface Cell { R rowKey(); C columnKey(); diff --git a/src/com/landawn/abacus/util/stream/StreamBase.java b/src/com/landawn/abacus/util/stream/StreamBase.java index d15b51b7..ac0d8519 100644 --- a/src/com/landawn/abacus/util/stream/StreamBase.java +++ b/src/com/landawn/abacus/util/stream/StreamBase.java @@ -32,6 +32,7 @@ import com.landawn.abacus.logging.Logger; import com.landawn.abacus.logging.LoggerFactory; +import com.landawn.abacus.util.Sheet; import com.landawn.abacus.util.AsyncExecutor; import com.landawn.abacus.util.BiMap; import com.landawn.abacus.util.BooleanList; @@ -63,7 +64,6 @@ import com.landawn.abacus.util.MutableBoolean; import com.landawn.abacus.util.N; import com.landawn.abacus.util.ObjectList; -import com.landawn.abacus.util.Sheet; import com.landawn.abacus.util.ShortIterator; import com.landawn.abacus.util.ShortList; import com.landawn.abacus.util.Try; @@ -694,17 +694,17 @@ protected DoubleStream newStream(final DoubleIterator iter, final boolean sorted protected Stream newStream(final E[] a, final boolean sorted, final Comparator comparator) { if (this.isParallel()) { - return new ParallelArrayStream(a, 0, a.length, closeHandlers, sorted, comparator, this.maxThreadNum(), this.splitor()); + return new ParallelArrayStream<>(a, 0, a.length, closeHandlers, sorted, comparator, this.maxThreadNum(), this.splitor()); } else { - return new ArrayStream(a, closeHandlers, sorted, comparator); + return new ArrayStream<>(a, closeHandlers, sorted, comparator); } } protected Stream newStream(final Iterator iter, final boolean sorted, final Comparator comparator) { if (this.isParallel()) { - return new ParallelIteratorStream(iter, closeHandlers, sorted, comparator, this.maxThreadNum(), this.splitor()); + return new ParallelIteratorStream<>(iter, closeHandlers, sorted, comparator, this.maxThreadNum(), this.splitor()); } else { - return new IteratorStream(iter, closeHandlers, sorted, comparator); + return new IteratorStream<>(iter, closeHandlers, sorted, comparator); } }